Is there a better way to mass tween?

Hey! So I’ve just recently started a new project, and I’m looking to mass tween in all of my active UI elements within my character customization UI.

However, the way that I am doing this seems wildly inefficient and I was wondering if I could get some opinions from others on how you’d recommend refactoring this. I’ll leave the related code snippet below, thanks!

for i,v in pairs(customizationUI:GetDescendants()) do
		if v.ClassName == "Frame" or v.ClassName == "TextLabel" then
			v.Visible = false
		end
	end
	
	local savedTransparencies = {}
	local savedTransparenciesTwo = {}
	
	for i,v in pairs(customizationUI.ActiveElements:GetDescendants()) do
		if v.ClassName == "Frame" then
			table.insert(savedTransparencies, {v, v.BackgroundTransparency})
			v.BackgroundTransparency = 1
			v.Visible = true
		end
		if v.ClassName == "TextLabel" then
			table.insert(savedTransparencies, {v, v.TextTransparency})
			table.insert(savedTransparenciesTwo, {v, v.BackgroundTransparency})
			v.TextTransparency = 1
			v.BackgroundTransparency = 1
			v.Visible = true
		end
	end
	
	local savedTweens = {}
	
	for i,v in pairs(savedTransparencies) do
		local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Quart, Enum.EasingDirection.InOut)
		if v[1].ClassName == "Frame" then
			table.insert(savedTweens, tweenService:Create(v[1], tweenInfo, {BackgroundTransparency = v[2]}))
		end
		
		if v[1].ClassName == "TextLabel" then
			table.insert(savedTweens, tweenService:Create(v[1], tweenInfo, {TextTransparency = v[2]}))
		end
	end
		
	for i,v in pairs(savedTransparenciesTwo) do
		local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Quart, Enum.EasingDirection.InOut)
		table.insert(savedTweens, tweenService:Create(v[1], tweenInfo, {BackgroundTransparency = v[2]}))
	end
	
	customizationUI.Enabled = true
	
	for i,v in pairs(savedTweens) do
		v:Play()
	end
  • anythingoliver

Make sure to use canvas groups. They have a property called GroupTransparency, which gives you control over all the descendant’s transparencies.

You also don’t have to deal with tweening an element’s background transparency, text transparency or stroke transparency seperately.

1 Like

Would this also work for Text Transparency? I’m pretty sure that only works on the background. I am not too experienced with UI design, so I’m asking for myself and for others who may be looking at this thread in the future.

Honestly would only agree with using canvas groups if it weren’t for them being more computationally expensive. So it should only be used for niche things like mini-maps or some type of effects. Otherwise you might incur performance issues.

@LeilaStardust To answer your question, it groups all descendants into being rendered with canvas properties & local properties, so yes it also effects text, stroke, image and other transparencies. It also fixes geometry with “ClippedDescendants” that normal GuiObjects either used to have or currently have when there’s a rotation applied.


The way I’ve gone about this was creating a ‘group’ object (Not a roblox instance) which I can insert GuiObjects into it and set object specific tween properties. It’s basically just looping through a list of these grouped GuiObjects and either tweens in to the properties or tweens back to it’s default/pre-applied properties depending on what method you use :Tween() :Reverse().

Realistically this doesn’t change anything, just organizes instances into a group then you can easily do group:DoSomething and it applies whatever you want to the group.

This is just an example of the code incase you want an idea:

-- // This is the group object
-- // local group = class.new("MENU_GROUP") || Ex
function methods:Revert()
	-- // Reverts to pre-applied properties
end

function methods:Tween(tweenInfo : TweenInfo?)
	-- // Tweens into the properties either provided or pre applied
end

-- // Creates or returns a new GUI group
function class.createFrameGroup(group_name : string)
	assert(typeof(group_name) == "string", "Group name not provided.")
	if (class.Groups[group_name]) then return class.Groups[group_name] end
	
	local self = setmetatable({}, methods)
	
	self.Name = group_name
	self.Defaulted = true
	self.PropertySnapping = false
	self.OptimizationMode = false
	self.ForceTweenOnRevert = true
	self.TweenOnlyWhenVisible = true
	
	self._tweenInfo = TweenInfo.new(.1)
	self._frames = {}
	self._settings = {}
	self._classProperties = {}
	self._currentTweening = {}
	self._connections = {} -- // Being used for descendants adding / removing
	
	self._OnComplete = Instance.new("BindableEvent")
	self.OnComplete = HookSignal(self._OnComplete.Event) :: RBXScriptSignal
	self.PlaybackState = Enum.PlaybackState.Completed :: Enum.PlaybackState
	
	self.OnComplete:Connect(function()
		table.clear(self._currentTweening)
	end)
	
	class.Groups[self.Name] = self
	
	return self
end

In theory you can even do this:

local function TweenAll(...)
	return function()
		for i = 1, select("#", ...) do
			local tween = select(i, ...)
			if not (typeof(tween) == "Instance" and tween:IsA("Tween") then continue end
			tween:Play()
		end
	end
end

local Tween = TweenAll(tween1, tween2, tween3)

I’m not sure if any of this helps but hopefully gives any idea even if it’s not exactly what you were hoping.

2 Likes

Yes, GroupTransparency applies to text too, as said here:

1 Like