After experimenting with TextService:GetTextSize()
for a while, I figured out how to use that to cycle through various TextSize
values until it fit within the AbsoluteSize
of the TextLabel
at a given size.
However, I later realized that there’s a TextFits
property, which is automatically set to true
when all of the text fits within the bounds of the TextLabel
. This simplifies things a bit, as you wouldn’t need to use TextService:GetTextSize()
at all.
Because there are good use cases for both (with the first option making it possible for you to determine its TextBounds
, which provides you with the opportunity to increase the Size
of the TextLabel
to accommodate all the text rather than decreasing the TextSize
), I’ll include both variations in this post.
The first completed codeblock will be the “simpler” version that better matches the use case you described and the second codeblock will be the one that uses TextService:GetTextSize()
if you want to really really make sure the text fits and / or to have more flexibility.
Since you didn’t include the code for the typewriter effect in your original post, I utilized the example code snippet from the Roblox Creator Documentation site and integrated that into the completed product to test your use case.
Before I explain how it works, here’s the full script:
(Simple Version: Only checking for TextFits
) Completed LocalScript code
local TweenService = game:GetService("TweenService")
local textLabel = script.Parent
local maximumTextSize = 100 -- Update this to the largest possible value you would want the "TextSize" property to be
local testingText = {
[1] = "Hello world!",
[2] = "Here is an example string with a lot more text than the previous one.",
[3] = "Isn't that cool?"
}
local typewriterTweenInfo = TweenInfo.new(4, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
local previewTextSizeChanges = false -- If you want to visualize the Text as the script is trying to find out a suitable TextSize, change this to true (mostly for testing purposes)
local function typewriter(originalText)
if previewTextSizeChanges == true then -- Mostly for testing purposes!
textLabel.MaxVisibleGraphemes = -1
else
textLabel.MaxVisibleGraphemes = 0
end
textLabel.Text = originalText
local currentTextSize = maximumTextSize
local finalTextSize
while finalTextSize == nil do
task.wait()
textLabel.TextSize = currentTextSize
if textLabel.TextFits == true then
finalTextSize = currentTextSize
else
currentTextSize -= 1
end
end
textLabel.TextSize = finalTextSize
if previewTextSizeChanges == true then -- Mostly for testing purposes!
task.wait(2) -- Small delay before starting the typewriter effect to visualize how the final text will appear at what was determined to be a suitable TextSize
end
local tween = TweenService:Create(textLabel, typewriterTweenInfo, {
MaxVisibleGraphemes = utf8.len(textLabel.ContentText),
})
tween:Play()
tween.Completed:Wait()
end
for _, textToAnimate in testingText do
typewriter(textToAnimate)
end
Completed LocalScript code
local TweenService = game:GetService("TweenService")
local TextService = game:GetService("TextService")
local textLabel = script.Parent
local maximumTextSize = 100 -- Update this to the largest possible value you would want the "TextSize" property to be
local testingText = {
[1] = "Hello world!",
[2] = "Here is an example string with a lot more text than the previous one.",
[3] = "Isn't that cool?"
}
local typewriterTweenInfo = TweenInfo.new(4, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)
local previewTextSizeChanges = false -- If you want to visualize the Text as the script is trying to find out a suitable TextSize, change this to true (mostly for testing purposes)
local function typewriter(originalText)
if previewTextSizeChanges == true then -- Mostly for testing purposes!
textLabel.MaxVisibleGraphemes = -1
else
textLabel.MaxVisibleGraphemes = 0
end
textLabel.Text = originalText
local currentTextSize = maximumTextSize
local font = textLabel.Font
local absoluteSize = textLabel.AbsoluteSize
local finalTextSize
while finalTextSize == nil do
task.wait()
textLabel.TextSize = currentTextSize
local requiredSpace = TextService:GetTextSize(originalText, currentTextSize, font, absoluteSize)
if
requiredSpace.X <= absoluteSize.X
and requiredSpace.Y <= absoluteSize.Y
and textLabel.TextFits == true
then
finalTextSize = currentTextSize
else
currentTextSize -= 1
--print(requiredSpace.X, requiredSpace.Y, absoluteSize.X, absoluteSize.Y)
--print(currentTextSize)
end
end
textLabel.TextSize = finalTextSize
if previewTextSizeChanges == true then -- Mostly for testing purposes!
task.wait(2) -- Small delay before starting the typewriter effect to visualize how the final text will appear at what was determined to be a suitable TextSize
end
local tween = TweenService:Create(textLabel, typewriterTweenInfo, {
MaxVisibleGraphemes = utf8.len(textLabel.ContentText),
})
tween:Play()
tween.Completed:Wait()
end
for _, textToAnimate in testingText do
typewriter(textToAnimate)
end
Instructions
-
If the script that contains the code is not placed directly into the TextLabel
that you want to preview text for, make sure to update the local textLabel
variable to reference where the TextLabel
is in the game.
-
Update the “maximumTextSize” to the largest possible value you would want the “TextSize” property to be. It’s at 100 by default since that’s the maximum value you can input via the Properties window.
-
Optionally, update the local previewTextSizeChanges
variable from false
to true
(right above local function typewriter
) if you want to visualize the Text as the script is trying to find out a suitable TextSize (mostly for testing purposes). For the most noticeable effect, make the TextLabel
smaller so that the TextSize
will have to be decreased to an even lower value.
Also, because this is an example, the function that handles everything runs immediately after beginning a playtest. As a result, additional changes would be necessary to properly integrate this into your game.
How the “preview” works
for _, textToAnimate in testingText do
typewriter(textToAnimate)
end
The text that you want to find the optimal size for is sent through to the typewriter
function (and in this case, it’s everything included within the testingText
table).
if previewTextSizeChanges == true then -- Mostly for testing purposes!
textLabel.MaxVisibleGraphemes = -1
else
textLabel.MaxVisibleGraphemes = 0
end
textLabel.Text = originalText
Since we’re creating a typewriter effect, the text is hidden by setting TextLabel.MaxVisibleGraphemes
to 0. After that, the Text
property of the TextLabel
is updated to the string that was sent through the function.
local currentFontSize = maximumTextSize
local font = textLabel.Font
local absoluteSize = textLabel.AbsoluteSize
These 3 variables have the following purposes:
-
currentFontSize initially refers to the value of
maximumTextSize
at the top of the script. This is the first value that is used when checking if the text fits in the TextLabel
. If it doesn’t, the value is continuously lowered and the TextSize
is updated to the new value until it’s able to fit in the TextLabel
.
(The last 2 variables are only included in the second version of the script because they are necessary for TextService:GetTextSize()
)
-
font refers to the TextLabel.Font
that is currently being used to make sure the script will be accurately checking how much space will be necessary . If you intend to swap the font at different points in time, I’d recommend doing so before it reaches this point in the function (around the time that textLabel.Text = originalText
is assigned). However, if you’re using the simpler version of the script, this wouldn’t be necessary.
-
absoluteSize refers to the AbsoluteSize
of the TextLabel
, which basically says what the resolution of the TextLabel
is on the current screen. This will differ for the same object depending on the size of the screen.
local finalTextSize
while finalTextSize == nil do
The finalTextSize
variable is where the value of the new TextSize
will be stored once the script figures out the largest possible TextSize
where all of the text is visible. We create a loop that continues as long as finalTextSize == nil
(meaning that there’s no value for it yet).
-- This is what the loop looks like in the simpler version
while finalTextSize == nil do
task.wait()
textLabel.TextSize = currentTextSize
if textLabel.TextFits == true then
finalTextSize = currentTextSize
else
currentTextSize -= 1
end
end
I’ll start by explaining the loop in the simpler version, as it’ll make it easier to explain the second one afterward.
We start by adding a task.wait()
to make sure the game doesn’t freeze from the loop running too quickly. Then, we update the TextSize
of the TextLabel
to the value stored in the currentTextSize
variable outside of the loop.
Next, we check if the TextFits
property of the TextLabel
is equal to true
. If it doesn’t, that means the text doesn’t fit within the TextLabel
, which means we move on to the else
statement that decreases the currentTextSize
variable by 1. If that happens, the loop will restart and try again.
If TextFits
ends up equalling true
, we know that all of the Text
is visible at its current TextSize
. From there, we update the finalTextSize
variable to equal the currentTextSize
, which will end the loop on the next iteration and continue with the script.
-- This is what the loop looks like in the alternative version
while finalTextSize == nil do
task.wait()
textLabel.TextSize = currentTextSize
local requiredSpace = TextService:GetTextSize(originalText, currentTextSize, font, absoluteSize)
if
requiredSpace.X <= absoluteSize.X
and requiredSpace.Y <= absoluteSize.Y
and textLabel.TextFits == true
then
finalTextSize = currentTextSize
else
currentTextSize -= 1
--print(requiredSpace.X, requiredSpace.Y, absoluteSize.X, absoluteSize.Y)
--print(currentTextSize)
end
end
The alternative version is almost identical to the previous one, except that there’s additional values that are checked for. In this case, TextService:GetTextSize()
is being used to check how much space is required for all of the Text
to fit within the TextLabel
. We can use that value to compare it to the current AbsoluteSize
of the TextLabel
; if it’s less than that, then we know the Text
probably fits within the TextLabel
. However, in some cases, it still did not fit within the TextLabel
, which is when I found out about the TextFits
property and added that in.
Ultimately, checking for all 3 of these things is not really necessary (since you can just reference TextFits
), but you can do that if you want to be super sure that all of the Text
will be visible. And as mentioned at the beginning of this post, using TextService:GetTextSize()
does provide the opportunity to increase the Size
of the TextLabel
until it reaches an AbsoluteSize
that would accommodate the text, which may be useful if you want to ensure the text remains readable without decreasing the TextSize
.
textLabel.TextSize = finalTextSize
After the loop finishes, we can update the TextSize
of the TextLabel
to the finalTextSize
, which should be the largest value it can be while making sure all of the text is visible.
if previewTextSizeChanges == true then -- Mostly for testing purposes!
task.wait(2) -- Small delay before starting the typewriter effect to visualize how the final text will appear at what was determined to be a suitable TextSize
end
local tween = TweenService:Create(textLabel, typewriterTweenInfo, {
MaxVisibleGraphemes = utf8.len(textLabel.ContentText),
})
tween:Play()
tween.Completed:Wait()
end
The code at the very end of the function handles the typewriter effect with the newly configured TextLabel
(and as mentioned earlier, the original typewriter example can be found in a code snippet from the Roblox Creator Documentation site.
And I think that’s everything! Hopefully this was useful and the explanations made sense
I’ve been working on this for several hours past midnight, so if I completely forgot to explain something or you have any questions, feel free to ask and I’ll try to respond once I am fully rested.