Hey developers!
I’ve been getting into advanced UI transitions lately and couldn’t find anything on how to automatically tween transparency transitions.
It’s a lot harder than you think. Simply changing the holder object’s transparency won’t do the same for its children. There’s one way to work around it: CanvasGroups.
But there are downsides to using CanvasGroups, such as reduced performance and whatever GroupColor3 is making random objects transparent.
Another way is to just hardcode everything. Just a bunch of tweens, like this:
tweenService:Create(object, tweenInfo, {Transparency = 1}):Play()
tweenService:Create(anotherObject, tweenInfo, {Transparency = 1}):Play()
tweenService:Create(someObject, tweenInfo, {Transparency = 1}):Play()
tweenService:Create(moreObject, tweenInfo, {Transparency = 1}):Play()
tweenService:Create(someOtherObject, tweenInfo, {Transparency = 1}):Play()
tweenService:Create(infiniteObject, tweenInfo, {Transparency = 1}):Play()
But this isn’t very efficient to code, and is bad practice. It’s a bad habit that will be detrimental for you in the long term.
So, I have created an algorithm that will achieve this transition without using CanvasGroups. That’s what I’m going to teach you to create today.
- Create a table to store the original transparencies of the GuiObjects. My example:
local originalTransparencies = {}
Then, make an array containing all transparency-related properties. I believe it is the following:
local transparencyProperties = {
"BackgroundTransparency",
"TextTransparency",
"TextStrokeTransparency",
"Transparency",
"ImageTransparency",
"GroupTransparency",
"ScrollBarImageTransparency"
}
(Let me know if there’s anything missing).
- Write a function that allows you to check if a property exists on an instance. My example:
local function checkForProperty(object, property)
local foundProperty = nil
local success = pcall(function()
foundProperty = object[property]
end)
if success then
return foundProperty
else
return false
end
end
Now we’re getting into the good stuff.
- Write a function that will tween properties on an object. There are two different ways it will tween: through a dictionary containing the original transparencies of the objects, or creating that dictionary containing the original transparencies, tweening those properties to
1
, and returning that dictionary we created.
My example:
local function tweenProperties(object, tweenInfo, originalTransparencies)
if originalTransparencies then
tweenService:Create(object, tweenInfo, originalTransparencies):Play()
else
local originalTransparency = {}
local tweenProperties = {}
for _, property in ipairs(transparencyProperties) do
local propertyValue = checkForProperty(object, property)
if propertyValue then
if object:IsA("TextLabel") and property == "Transparency" then continue end -- Exception I had to make
originalTransparency[property] = propertyValue
if propertyValue < 1 then
tweenProperties[property] = 1
end
end
end
tweenService:Create(object, tweenInfo, tweenProperties):Play()
return originalTransparency
end
end
(If any of you are wondering about that TextLabel line, there is a property called Transparency that was interfering.)
Finally, we can create the function that will actually transition.
- Write a function to transition a GuiObject. It will have 3 parameters: the holder GuiObject, the direction of the transition (is it transitioning in or out?), and an (optional) TweenInfo object to tween properties with.
If the direction is transitioning in, you will tween the properties of the holder frame using the original transparencies. Then loop through its descendants and do the same. Use this line:
if not object:IsA("GuiObject") then continue end
to skip objects that aren’t GuiObjects.
If the direction is transitioning out, you will tween the properties of the holder frame, and define the original transparency table it returns as a variable. Then you will set that original transparencies dictionary we created in step 1 to that variable. Do the same for it’s descendants, and you are finished.
My example:
local function transition(holder: GuiObject, direction: number, tweenInfo: TweenInfo)
if direction == 1 then
tweenProperties(holder, tweenInfo, originalTransparencies[holder])
for _, object in ipairs(holder:GetDescendants()) do
if not object:IsA("GuiObject") then continue end
if originalTransparencies[object] then
tweenProperties(object, tweenInfo, originalTransparencies[object])
end
end
elseif direction == 2 then
local holderOriginalTransparency = tweenProperties(holder, tweenInfo)
originalTransparencies[holder] = holderOriginalTransparency
for _, object in ipairs(holder:GetDescendants()) do
if not object:IsA("GuiObject") then continue end
local originalTransparency = tweenProperties(object, tweenInfo)
originalTransparencies[object] = originalTransparency
end
end
end
Finally, you are done. Your end script should look something like this:
local tweenService = game:GetService("TweenService")
local originalTransparencies = {}
local transparencyProperties = {
"BackgroundTransparency",
"TextTransparency",
"TextStrokeTransparency",
"Transparency",
"ImageTransparency",
"GroupTransparency",
"ScrollBarImageTransparency"
}
local function checkForProperty(object, property)
local foundProperty = nil
local success = pcall(function()
foundProperty = object[property]
end)
if success then
return foundProperty
else
return false
end
end
local function tweenProperties(object, tweenInfo, originalTransparencies)
if originalTransparencies then
tweenService:Create(object, tweenInfo, originalTransparencies):Play()
else
local originalTransparency = {}
local tweenProperties = {}
for _, property in ipairs(transparencyProperties) do
local propertyValue = checkForProperty(object, property)
if propertyValue then
if object:IsA("TextLabel") and property == "Transparency" then continue end -- Exception I had to make
originalTransparency[property] = propertyValue
if propertyValue < 1 then
tweenProperties[property] = 1
end
end
end
tweenService:Create(object, tweenInfo, tweenProperties):Play()
return originalTransparency
end
end
local function transition(holder: GuiObject, direction: number, tweenInfo: TweenInfo)
if direction == 1 then
tweenProperties(holder, tweenInfo, originalTransparencies[holder])
for _, object in ipairs(holder:GetDescendants()) do
if not object:IsA("GuiObject") then continue end
if originalTransparencies[object] then
tweenProperties(object, tweenInfo, originalTransparencies[object])
end
end
elseif direction == 2 then
local holderOriginalTransparency = tweenProperties(holder, tweenInfo)
originalTransparencies[holder] = holderOriginalTransparency
for _, object in ipairs(holder:GetDescendants()) do
if not object:IsA("GuiObject") then continue end
local originalTransparency = tweenProperties(object, tweenInfo)
originalTransparencies[object] = originalTransparency
end
end
end
And here it is in action:
I’ve also created a module that you can use instead:
It’s only got one function: .transition(holder: GuiObject, direction: number, tweenInfo: TweenInfo)
.
Good luck with your UI!
Fizzitix