Getting text height to size box correctly

Trying to create a custom chat, and problems I face are when a message is too long, the text just goes small, instead of doing what the Roblox chat does, create a second/third line etc.

I did some testing in studio, and found that just doubling the frame the text is in size, it seems to look/work good.

So how I set the frames up

local MessasgeFrame = Instance.new('Frame')
MessasgeFrame.AnchorPoint = Vector2.new(0.5, 1)
MessasgeFrame.BackgroundTransparency = 1
MessasgeFrame.Position = UDim2.new(0.5, 0, 1, 0)
MessasgeFrame.Size = UDim2.new(1, 0, 0.1, 0) -- Get message length/adjust height

local Message = Instance.new('TextLabel')
Message.AnchorPoint = Vector2.new(0.5, 0.5)
Message.BackgroundTransparency = 1
Message.Position = UDim2.new(0.5, 0, 0.5, 0)
Message.Size = UDim2.new(0.95, 0, 0.9, 0)
Message.Font = Enum.Font.GothamSemibold
Message.Text = tostring(speaker) .. ': ' .. message
Message.TextColor3 = Color3.fromRGB(255, 255, 255)
Message.TextScaled = true	
Message.TextXAlignment = Enum.TextXAlignment.Left
Message.TextYAlignment = Enum.TextYAlignment.Top

So I need to know how I can figure out how tall the frame needs to be. Default is 0.1, but as the longer texts gets, I add 0.1. And I want to limit the message so if it gets to 0.3, then the message just gets cut off

5 Likes

You can calculate text bounds by using TextService:GetTextSize. I was having a similar problem a while ago and found a solution by digging into the default Roblox chat script. You can read my thread here which contains how Roblox handles their chat lines.

5 Likes

I was just looking at that, however I need to get a ‘FontSize’ parameter. I’m using TextScaled, so there is no ‘FontSize’ (well Idk how to get the fontsize for a scaled text label)

You probably shouldn’t be using TextScaled if you want to achieve a chat system which automatically changes the size of frames depending on the amount of text. Instead of scaling the text, you want to change the size of the frame on the Y axis to account for the amount of text in the player’s message. In order to achieve this, you need to stick to one certain text size.


If you’re interested, here is how I calculate the size of my message frames:

local function measureSize(textObject)
	return TextService:GetTextSize(textObject.Text, textObject.TextSize, textObject.Font, Vector2.new(textObject.AbsoluteSize.X, 10000))
end

frame.Username.Size = UDim2.new(0, frame.Username.TextBounds.X, 0, 20)
frame.Message.Text = string.rep(" ", math.ceil(measureSize(frame.Username).X / TextService:GetTextSize(" ", frame.Username.TextSize, frame.Username.Font, Vector2.new(5000, 5000)).X) + 1) .. message
frame.Size = UDim2.new(1, 0, 0, measureSize(frame.Message).Y)
4 Likes
print(game:GetService('TextService'):GetTextSize(message, 16, Enum.Font.GothamSemibold, Message.AbsoluteSize))

Returns a different X value, but the Y value is consistenly 16

By using Message.AbsoluteSize you are restricting the text to only be as long as the message frame. You want to set the maximum Y value to a large number, here is an example of a Vector2 you should use:

Vector2.new(Message.AbsoluteSize.X, 10000)
1 Like
print(game:GetService('TextService'):GetTextSize(message, 16, Enum.Font.GothamSemibold, Vector2.new(Message.AbsoluteSize.X, 10000)))

Still returns 16 for Y value

local MessageFrame = Instance.new('Frame')
	MessageFrame.AnchorPoint = Vector2.new(0.5, 1)
	MessageFrame.BackgroundTransparency = 1
	MessageFrame.Position = UDim2.new(0.5, 0, 1, 0)
	MessageFrame.Size = UDim2.new(0.9, 0, 0.1, 0)
	
	local PlayerLabel = Instance.new('TextLabel')
	PlayerLabel.AnchorPoint = Vector2.new(0.5, 0.5)
	PlayerLabel.BackgroundTransparency = 1
	PlayerLabel.Position = UDim2.new(0, 0, 0.5, 0)
	PlayerLabel.Font = Enum.Font.GothamSemibold
	PlayerLabel.Text = tostring(speaker)
	PlayerLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	PlayerLabel.TextSize = 16
	PlayerLabel.TextXAlignment = Enum.TextXAlignment.Left
	PlayerLabel.TextYAlignment = Enum.TextYAlignment.Top
	
	local Message = Instance.new('TextLabel')
	Message.AnchorPoint = Vector2.new(0.5, 0.5)
	Message.BackgroundTransparency = 1
	Message.Position = UDim2.new(0.5, 0, 0.5, 0)
	Message.Size = UDim2.new(0.95, 0, 0.9, 0)
	Message.Font = Enum.Font.GothamSemibold
	Message.Text = message
	Message.TextColor3 = Color3.fromRGB(255, 255, 255)
	Message.TextSize = 18
	Message.TextXAlignment = Enum.TextXAlignment.Left
	Message.TextYAlignment = Enum.TextYAlignment.Top
	
	local function measureSize(textObject)
		return game:GetService('TextService'):GetTextSize(textObject.Text, textObject.TextSize, textObject.Font, Vector2.new(textObject.AbsoluteSize.X, 10000))
	end

	PlayerLabel.Size = UDim2.new(0, PlayerLabel.TextBounds.X, 0, 18)
	Message.Text = ("%s%s"):format(string.rep(" ", math.ceil(measureSize(PlayerLabel).X / game:GetService('TextService'):GetTextSize(" ", PlayerLabel.TextSize, PlayerLabel.Font, Vector2.new(5000, 5000)).X) + 1), message)
	MessageFrame.Size = UDim2.new(0.95, 0, 0, measureSize(Message).Y)

This is what I got currently,


Doesn’t alter frame size still, and since I’ve now made the username a seperate label, it creates a large gap between the username and the message, as well as the message looking bigger than the username even tho they are the same size/font :confused:

1 Like

That’s strange, it is working perfectly fine for me. How is your frame currently set up? I have also edited the code you provided in the OP a bit and it is working as expected in studio. The size of the message inside the holder frame should be the same size as the holder frame on the Y axis, if you want to have spacing in between each frame I recommend using a UIListLayout or separately changing the position of each message frame.

local MessageFrame = Instance.new('Frame')
MessageFrame.AnchorPoint = Vector2.new(0.5, 1)
MessageFrame.BackgroundTransparency = 1
MessageFrame.Position = UDim2.new(0.5, 0, 1, 0)
MessageFrame.Size = UDim2.new(1, 0, 0, 16)

local Message = Instance.new('TextLabel')
Message.AnchorPoint = Vector2.new(0.5, 0.5)
Message.BackgroundTransparency = 1
Message.Position = UDim2.new(0.5, 0, 0.5, 0)
Message.Size = UDim2.new(0.95, 0, 1, 0)
Message.Font = Enum.Font.GothamSemibold
Message.Text = tostring(speaker) .. ': ' .. message
Message.TextSize = 16
Message.TextWrapped = true
Message.TextColor3 = Color3.fromRGB(255, 255, 255)
Message.TextXAlignment = Enum.TextXAlignment.Left
Message.TextYAlignment = Enum.TextYAlignment.Top
Message.Parent = MessageFrame

MessageFrame.Size = UDim2.new(1, 0, 0, TextService:GetTextSize(Message.Text, Message.TextSize, Message.Font, Vector2.new(MessageFrame.AbsoluteSize.X, 10000)).Y)

On another note, the only reason I was making a seperate text label for the player’s username was in order to have control over the color of the username and it is completely optional to do so. Since you are not trying to do something exclusively to the player’s username it is unnecessary to create a separate frame for it.

1 Like

I did end up creating a seperate label for the player username, because I ended up realising that it needed to be seperate in order to add like different colors/etc to it

Are you using TextWrapped? I feel like that may have something to do with your issue.

1 Like

TextScaled and TextWrapped are both on false for both the username and message.

Just doing some tests as to why the username label wasn’t being sized correctly

print(PlayerLabel.TextBounds.X) -- prints 0
PlayerLabel.Size = UDim2.new(0, PlayerLabel.TextBounds.X, 0, 18)

So its setting the size for X to be 0, not sure if this could be causing problems?

I think the reason the function GetTextSize is returning 16 always is due to the fact you have TextWrapped off. Since you’re manually setting the size of the TextLabel to 16, it’s always going to return that.

I’m tryingto use this instead now

local function measureSize(textObject)
		return game:GetService('TextService'):GetTextSize(textObject.Text, textObject.TextSize, textObject.Font, Vector2.new(textObject.AbsoluteSize.X, 10000))
	end
	print(PlayerLabel.TextBounds.X) -- prints 0
	PlayerLabel.Size = UDim2.new(0, PlayerLabel.TextBounds.X, 0, 16)
	Message.Text = ("%s%s"):format(string.rep(" ", math.ceil(measureSize(PlayerLabel).X / game:GetService('TextService'):GetTextSize(" ", PlayerLabel.TextSize, PlayerLabel.Font, Vector2.new(5000, 5000)).X) + 1), message)
	MessageFrame.Size = UDim2.new(0.95, 0, 0, measureSize(Message).Y)

Strange. I did the exact thing you did (except no player label), and it works fine. I think it’s an issue on your end. Although, I do think your chat text goes off of the chat frame due to you not using TextWrapped.

Setting TextWrapped to true does nothing
If the text is too long, it just doesn’t show up

You don’t seem to be using the script in that screenshot, and you put tons of spaces in the front of the text. TextWrapped is basically like ClipsDescendants for your text.

This is the full message creator

local function CreateMessage(message, speaker)
	local MessageFrame = Instance.new('Frame')
	MessageFrame.AnchorPoint = Vector2.new(0.5, 1)
	MessageFrame.BackgroundTransparency = 1
	MessageFrame.Position = UDim2.new(0.5, 0, 1, 0)
	MessageFrame.Size = UDim2.new(0.9, 0, 0.1, 0)
	
	local PlayerLabel = Instance.new('TextLabel')
	PlayerLabel.AnchorPoint = Vector2.new(0, 0.5)
	PlayerLabel.BackgroundTransparency = 1
	PlayerLabel.Position = UDim2.new(0, 0, 0.5, 0)
	PlayerLabel.Font = Enum.Font.GothamSemibold
	PlayerLabel.Text = tostring(speaker)
	PlayerLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	PlayerLabel.TextSize = 16
	PlayerLabel.TextXAlignment = Enum.TextXAlignment.Left
	
	local Message = Instance.new('TextLabel')
	Message.AnchorPoint = Vector2.new(0, 0.5)
	Message.BackgroundTransparency = 1
	Message.Position = UDim2.new(0, 0, 0.5, 0)
	Message.Size = UDim2.new(0.95, 0, 0.9, 0)
	Message.Font = Enum.Font.GothamSemibold
	Message.Text = message
	Message.TextColor3 = Color3.fromRGB(255, 255, 255)
	Message.TextSize = 16
	Message.TextWrapped = true
	Message.TextXAlignment = Enum.TextXAlignment.Left
	
	local function measureSize(textObject)
		return game:GetService('TextService'):GetTextSize(textObject.Text, textObject.TextSize, textObject.Font, Vector2.new(textObject.AbsoluteSize.X, 10000))
	end
	
	print(Message.TextBounds.X)
	PlayerLabel.Size = UDim2.new(0, PlayerLabel.TextBounds.X, 0, 16)
	Message.Text = ("%s%s"):format(string.rep(" ", math.ceil(measureSize(PlayerLabel).X / game:GetService('TextService'):GetTextSize(" ", PlayerLabel.TextSize, PlayerLabel.Font, Vector2.new(5000, 5000)).X) + 1), message)
	MessageFrame.Size = UDim2.new(0.95, 0, 0, measureSize(Message).Y)

	PushMessages(MessageFrame.Size.Y.Scale)
	
	Chats[#Chats + 1] = MessageFrame
	
	PlayerLabel.Parent = Message
	Message.Parent = MessageFrame

	MessageFrame.Parent = List
end

What you are doing should work perfectly, yet it doesn’t. I think it is an issue on your end because it works fine for me. Except, what is PushMessages?