TextService - GetTextSize

a guide to sizing your text

by Danrich123

Author Avatar

Introduction

If you're creating a game, there's going to be one point where you want to dynamically create text on the screen. One way to approach this is by creating a TextLabel and parenting it to a ScreenGui. Set it's text, size, and make TextScaled true and you're done.

local label = Instance.new("TextLabel")
label.Text = "quick and simple"
label.TextScaled = true
label.Size = UDim2.fromOffset(300, 50) -- let's ignore that

label.Parent = screenGui

img|2405x545

Not very appealing, but if you add a little style it's going to look good, right? Right? 😡

label.BorderSizePixel = 0
label.BackgroundColor3 = Color3.new(0, 0, .1)
label.BackgroundTransparency = .4

label.AnchorPoint = Vector2.new(.5, 0)
label.Position = UDim2.new(.5, 0, .04, 0)
label.Font = Enum.Font.GothamSemibold
label.TextColor3 = Color3.fromRGB(255, 255, 255)

img|2330x455

Ok, that looks nice. But the text isn't always going to be the same in a game (presumably). So what if you make the text something else?

label.Text = enemyTeam .. " has captured the flag!" -- assuming enemyTeam is blue

or maybe

label.Text = "bought '" .. itemName .. "'"  -- assuming itemName is sword

img|2385x950

Individually they look nice, but together they're a little ugly. That's because of the inconsistent sizing. The paddings don't match and the text from the label below is almost two times bigger than the one above. It's not the end of the world, but you can do better. So how do you fix this? You can't really control the text size since it's TextScaled, and even if you disable TextScaled, the inconsistent padding is still going to be there.

Meet TextService

TextService has two useful functions: FilterStringAsync and GetTextSize. The one that's going to be used for this is GetTextSize. Like its name says, GetTextSize gives you the dimensions of some text as a Vector2 in offset. It accepts the arguments:

TextService:GetTextSize(text: string, textSize: number, font: Enum.Font, boundary: Vector2)

Breakdown! 😎

1. Text

duh, it's the text you want to find the dimensions of.

2. TextSize

Size of the text you want to find the dimensions of. Make sure it's an integer.

3. Font

Font of the text you want to find the dimensions of. Like Enum.Font.GothamSemibold

4. Boundary

The boundaries of the text you want to find the dimensions of. Used to see how the text will wrap. Really only the X component of it matters.

So why GetTextSize?

There are two obvious ways of approaching the problem of text size. The first one is to scale the text to the background (TextScaled), and the second is to scale the background to the text. Using GetTextSize, you can scale the background to the text. So first you have to find the size of the text (the TextSize!!!!! hey that's an argument of gettextsize).

Getting the TextSize

If you're concerned about scaling to different screen sizes, you're not just going to put some random number as the TextSize. You're going to have a text size that corresponds to the screen size. The most obvious way is to have the TextSize be some percentage of the screen size, and that's what you're going to do. Since TextSize is proportional to text height you'll want to scale based on the Y-axis (height). For this example you'll make the text size 5% of the screen height.

function getTextSize()
    return workspace.CurrentCamera.ViewportSize.Y * (5/100)
end

this works well, but if the player is on their phone and is in portrait mode, the text is going to be way to bloated. The solution is to scale based on the shortest axis, which in most cases is going to be the Y-axis as intended.

function getTextSize()
    return math.min(workspace.CurrentCamera.ViewportSize.X, workspace.CurrentCamera.ViewportSize.Y) * (5/100)
end

Getting the boundary

If you have a lot of text it's going to go off the screen, so you need to set a boundary. All the boundary does is specify how long the text is going to be before it wraps. The boundary is going to be proportional to the X-axis because English is written from left to right. For this it's going to be 70% of the screen.

function getBoundary()
    return Vector2.new(workspace.CurrentCamera.ViewportSize.X * (70/100), math.huge) -- y-axis is math.huge so the text never gets cut-off
end

Now you actually get to use GetTextSize

Now that you have all the ingredients you need for GetTextSize, just plug in the values and you'll get the dimensions for your text. Once you do that, adjust the size of your TextLabel to the dimensions of the text.

local textService = game:GetService("TextService")
local textSize = getTextSize()
local boundary = getBoundary()
local text = enemyTeam .. " has captured the flag!"
local font = Enum.Font.GothamSemibold

local textDimensions = text:GetTextSize(text, textSize, font, boundary)
label.Size = UDim2.fromOffset(textDimensions.X, textDimensions.Y)
label.TextWrapped = true
label.TextSize = textSize
label.Font = font
label.Text = text

img|4340x1010

Unfortunately there's no padding anymore. To add padding, all you have to do is change:

label.Size = UDim2.fromOffset(textDimension.X, textDimensions.Y)

to:

local paddingX = 5
local paddingY = 5
label.Size = UDim2.fromOffset(textDimensions.X + paddingX*2, textDimensions.Y + paddingY*2) -- multiply by 2 so padding is applied on both sides

and done. That's how you size your text nicely.

img|2510x980

Now what?

GetTextSize gives you the dimensions of some text, so it's really useful for anything related to text. Maybe you want to make something like Lua Learning. Use GetTextSize. Dynamically styled text? GetTextSize. It's really useful.

tl;dr: there's a secret function called danceMonkey that automatically scales your TextLabels

View in-game to comment, award, and more!