Mutli-Line Chat With TextLabels

Hello how would I go about let’s say you have a custom chat, and the chat message is too long for one line, how would I go about making it a multi-line message with two TextLabels?

I know how I can do it by cutting a word in half, but how would I cut it from where the word that exceeds the line limit is at instead of just cutting a word in half?

3 Likes

An easy way to fix it is to just turn on TextScaled That way it will scale the text depending on the size of the text box.

1 Like

That’s not what I’m asking for.

2 Likes

Well let’s see here. I know there’s a property on any Text inherited instances, I think it’s called like TextFits. And what this does is it’ll turn off and on depending if the text fits in the text box or whatever. Perhaps you could toy around using this, running code each time the player adds a new piece of text to that text label or whatever it is you’re doing, seeing if the text fits, and if it doesn’t fit, then you could use string.sub and go up to how ever many characters were on the text BEFORE TextFits turned off, and then from that point you could get the other characters and then create a new text label out of it.

Wordy post. Hope it makes some sense atleast, lol.

1 Like

Roblox has given us a handy function to automate that process. The same TextService which allows us to filter text also has :GetTextSize() to find out how long a line of text will be. If it is too long, then divide it by the maximum line length and call math.ceil on it to get the number of lines. You can then resize the text label to span that many lines. You could also pass in a very large label height to GetTextSize and it will return the actual label height required for the given label width.

4 Likes

That’s what I’m doing right now, using that function and experimenting a little. I’ll tell you all when/if I figure this out.

1 Like

I figured it all out, no more help needed. :slight_smile:

2 Likes

Figured it out how? Please post your solution. Others may be attempting to figure out the same thing as you and need a solution as well.

12 Likes

Please @Avallachi, this is a really important issue. How did you manage to get it, just like @colbert2677 asked? It’s extremely difficult to do this, and I’m trying to do the same thing right now. But without directions on where to start, you can’t get it done. I know it was a year ago, but do you remember ± how the code worked?

1 Like

I quickly rewrote it to help out those who aren’t sure about how to implement multi-line support for their custom chat systems. The code I ended up with about 1.5 years ago contains a lot more “bad practices” and isn’t nearly as clean to read.

Essentially what I’m the script is doing is that it’s iterating through the message text and filling up a variable called PixelsSpent until it exceeds the variable PixelBudgetPerLine - which is basically how many pixels wide the text can be before it doesn’t fit in the message frame. So this is basically just text wrapping.

This code doesn’t try to keep whole words in the same line but can simply cut a word mid-through and continue on the next line - you’ll need to implement this yourself if wanted. It also automatically adjusts the ScrollingFrame’s CanvasSize and scrolls with it.

There also is no line nor text length limit - meaning your text can be as long as you want and infinitely make new lines.

I’m doing most of this in Offset and not Scale so if Scale is something you’d want, then you’ll have to add this yourself.

Video:

Code:

--||	Variables

local ScrollingFrame = script.Parent.ScrollingFrame
local TextService = game:GetService("TextService")

-- Config

local PixelsPerLine = 20

local PredefinedTextSize = 16
local PredefinedFont = Enum.Font.SourceSans

--||	Functions

function GetSize(String)
	return TextService:GetTextSize(String, PredefinedTextSize, PredefinedFont, Vector2.new(math.huge, math.huge)).X
end

function NewLabel(String, Position, Color)
	local Label = Instance.new("TextLabel")
	Label.BackgroundTransparency = 1
	Label.TextSize = PredefinedTextSize
	Label.Font = PredefinedFont
	Label.Text = String 
	Label.Position = Position
	Label.Size = UDim2.new(0, GetSize(String), 0, PixelsPerLine)
	Label.TextColor3 = Color or Color3.fromRGB(0, 0, 0)
	
	return Label
end

function NewMessage(Sender, MessageText)
	Sender = Sender .. ": "
	
	local Message = script.Template:Clone()
	Message.Parent = ScrollingFrame
	
	local PixelBudgetPerLine = Message.Container.AbsoluteSize.X
	local PixelsSpent = 0
	local Line = 0
	
	-- Sender
	
	local Label = NewLabel(Sender, UDim2.new(0, PixelsSpent, 0, 20*Line), Color3.fromRGB(92, 95, 255))
	Label.Parent = Message.Container
	PixelsSpent += GetSize(Sender)
	
	-- Message w/iterations
	
	local SubStart = 1
	
	for i = 1, #MessageText do
		local String = string.sub(MessageText, SubStart, i)
		local StringSize = GetSize(String)
		
		if PixelsSpent + StringSize > PixelBudgetPerLine then
			local String = string.sub(MessageText, SubStart, i-1)
			local StringSize = GetSize(String)
			
			local Label = NewLabel(String, UDim2.new(0, PixelsSpent, 0, 20*Line), Color3.fromRGB(43, 43, 43))
			Label.Parent = Message.Container
			
			PixelsSpent = 0
			Line += 1
			SubStart = i
			
			continue
		end
		
		if i == #MessageText then
			local Label = NewLabel(String, UDim2.new(0, PixelsSpent, 0, 20*Line), Color3.fromRGB(43, 43, 43))
			Label.Parent = Message.Container
		end
	end
	
	Message.Size = UDim2.new(Message.Size.X.Scale, Message.Size.X.Offset, 0, (Line+1) * PixelsPerLine)
	
	-- Scrolling frame
	
	ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, ScrollingFrame.UIListLayout.AbsoluteContentSize.Y)
	ScrollingFrame.CanvasPosition = Vector2.new(0, ScrollingFrame.CanvasSize.Y.Offset)
end

while wait(1) do
	NewMessage("Avallachi" .. math.random(1, 5000), "This is quite the long and unnecessary test message, but it's needed because I'm not very creative ;)")
end

Place file (.rblx)
chat.rbxl (25.0 KB)

I hope this was helpful to those of you who are still trying to figure this out.

10 Likes