Making text size consistent

Ok sure, here’s something pretty hastily made but from my testing it works. It has 2 options: first one is calculated automatically based on textLabel.TextBounds (needs textLabel.TextScaled enabled initially), second one is calculated manually. It does have a very slight size discrepancy depending on if you have a character below the base line (ie the lowercase letters g, q, p, y), but I’m not sure there’s much that can be done about that.

local textService = game:GetService('TextService')

local textSizeParams = Instance.new('GetTextBoundsParams')

local containerManual = script.Parent.Manual
local containerAuto = script.Parent.Auto

local function getSmallestSizeFactor() -- case of wanting to compute from the automatically calculated TextBounds
	-- get the maximum size factor of text that can fit in the label for all labels

	local minYFactor

	for _, container in containerAuto:GetChildren() do
		if not container:IsA('TextLabel') then
			continue
		end

		local isDoneCalculatingTextBounds = container.TextBounds ~= Vector2.zero

		if not isDoneCalculatingTextBounds then
			container:GetPropertyChangedSignal('TextBounds'):Wait()
		end

		local yAxisFactor = container.TextBounds.Y / container.AbsoluteSize.Y -- should give us a float between 0 and 1 which is the % height of the text in the label
		if not minYFactor or yAxisFactor < minYFactor then
			minYFactor = yAxisFactor
		end
	end

	return minYFactor
end

local function getSmallestSizeFactorManual() -- case of wanting to find the size manually
	local minYFactor
	
	for key, child in containerManual:GetChildren() do
		if not child:IsA('TextLabel') then
			continue
		end
		
		textSizeParams.Width = 0 -- 0 for no wrapping
		textSizeParams.Font = child.FontFace
		textSizeParams.Size = child.AbsoluteSize.Y
		textSizeParams.Text = child.Text
		
		local textBounds = textService:GetTextBoundsAsync(textSizeParams)
		local aspectRatio = textBounds.X / textBounds.Y
		
		-- now we have to scale it down to fit within textLabel.AbsoluteSize.X
		
		local requiredSize = child.AbsoluteSize.X / textBounds.X
		
		-- now we can multiply textBounds by requiredSize and it /should/ give us a new text bounds that fits within `child`'s bounds
		
		local multipliedTextBounds = textBounds * requiredSize
		
		-- now for the Y factor
		
		local yAxisFactor = multipliedTextBounds.Y / child.AbsoluteSize.Y
		
		if not minYFactor or yAxisFactor < minYFactor then
			minYFactor = yAxisFactor
		end
	end
	
	return minYFactor
end

-- USAGE:

local yFactor = getSmallestSizeFactorManual()

for _, child in containerManual:GetChildren() do
	if not child:IsA('TextLabel') then
		continue
	end

	local function handleChildChanged()
		child.TextSize = math.floor(yFactor * child.AbsoluteSize.Y) - 1 -- subtract 1 as safeguard. sometimes the last letter will get cut off by 1 pixel
	end

	child.TextScaled = false
	child:GetPropertyChangedSignal('AbsoluteSize'):Connect(handleChildChanged)
	handleChildChanged()
end

-- (auto)

local yFactor = getSmallestSizeFactor()

for _, child in containerAuto:GetChildren() do
	if not child:IsA('TextLabel') then
		continue
	end

	local function handleChildChanged()
		child.TextSize = math.floor(yFactor * child.AbsoluteSize.Y) - 1 -- subtract 1 as safeguard. sometimes the last letter will get cut off by 1 pixel
	end

	child.TextScaled = false
	child:GetPropertyChangedSignal('AbsoluteSize'):Connect(handleChildChanged)
	handleChildChanged()
end
4 Likes

Wow! This is amazing! Also, this might be a bit nitpicky but do you know why this happens?


The “passes” part is hidden but even if there is no fix for that, its still an amazing code. Thanks for the solution!

Looks like it might be because your labels are quite tall. Does that happen with the thing I provided? Trying now with the manual option, it doesn’t seem to be happening for me.

Make sure you’re using the manual one, TextScaled gets turned off, that you have TextWrapped off, and that you have text truncating off.

1 Like

The thing I did to fix this was to calculate yFactor in the handleChildChanged function so that when the absolute size changes it updates the yFactor

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.