How do I make a ScrollingFrame's CanvasSize adjust to the text within it?

I’m currently experimenting with making and scripting shop UI for a game. The UI is currently color-coded in bright colors in order to differentiate sections of the UI for debugging:


It looks ugly right now but just bear with me.

The blue section of the shop is a description bar that’s meant to display a text description of whatever item you’ve selected by clicking a button that appears in the green section. The description (not including the ImageLabel above it) is basically a ScrollingFrame with a TextLabel inside of it. I need the ScrollingFrame’s CanvasSize to change based on how much space the text inside of it is taking up, such that if the text starts to run off the bottom of the UI, the CanvasSize expands so that you can scroll down and still read it.

The ScrollingFrame has a CanvasSize of {0, 0}, {0, 0}, and its AutomaticCanvasSize = Y.
The TextLabel has a Size of {1, 0}, {0, 0}, and its AutomaticSize = Y. TextScaled = false, TextWrapped = true.

According to what I’ve read, this should be enough— but it isn’t. The text is meant to read “…clicking the X after talking to a shopkeeper”, but it still gets cut off at the bottom despite these settings. Supposedly having an AutomaticSize of Y for the TextLabel should make it scale based on the size of its text, but instead it just seems to make it scale to fill the size of the ScrollingFrame, which isn’t what I want. What do I have to change to make this work? Is a custom script necessary?

TextLabel.TextBounds

That should work very well in your case.
Make sure to connect :GetPropertyChangedSignal(“TextBounds”) aswell.

scrollingFrame.TextLabel:GetPropertyChangedSignal("TextBounds"):Connect(function()
	print("The TextBounds changed to", scrollingFrame.TextLabel.TextBounds)
	scrollingFrame.TextLabel.Size = UDim2.new(1,0, 0,scrollingFrame.TextLabel.TextBounds.Y)
end)

I turned off AutomaticSize for the TextLabel and now it’s stuck at 32px…

You are inputting scale instead of pixels.
TextBounds represent pixels.

Huh??

I’m setting the X scale to 1 so that it fills the ScrollingFrame. UDim2.new() has xScale, xOffset, yScale, yOffset. Even if I was setting the Y scale instead of the Y offset, wouldn’t it be like 32 times the size of the ScrollingFrame? Or are you referring to something else?

You are expected to do smth like:

local function Update():()
	print("The TextBounds changed to", scrollingFrame.TextLabel.TextBounds)
	scrollingFrame.TextLabel.Size = UDim2.new(1,0, 0,scrollingFrame.TextLabel.TextBounds.Y)
end
scrollingFrame.TextLabel:GetPropertyChangedSignal("TextBounds"):Connect(Update)
Update()

Oh wait- you actually did that right
image
Im sorry.

Well ig if i were to reply then i have to give some tip:

Wait you were not setting canvas size…

local TextLabel = scrollingFrame.TextLabel
local function Update():()
	print("The TextBounds changed to", TextLabel.TextBounds)
	scrollingFrame.CanvasSize = UDim2.new(1,0,0,TextLabel.TextBounds.Y)
end
TextLabel:GetPropertyChangedSignal("TextBounds"):Connect(Update)
Update()

I’m waiting to see if I can just let AutomaticCanvasSize deal with the scrolling part for me. If I understand it correctly, it should adjust it automatically according to the size of the TextLabel. What I’m having issues with right now is actually handling the TextLabel’s size. The official Roblox documentation makes it almost sound like TextBounds only detects the text that’s actually rendered, which means if the TextLabel isn’t already big enough, it gets cut off and then gets stuck…

Uh it should work for you, trust.
There is a mega hacky and semi broken way around
TextService:GetTextSize(“TextHere”,20,TextLabel.Font,Vector2.new(math.huge,math.huge))
But i don’t recomend using this one.

Oh dear god…

I mean it’s something to try, I honestly don’t know what else to do so I’ll see if I can use this and get it to work

Would using this work (assuming TextScaled is false)? You can get the height that the text needs to be in order to fit a certain width. It supports all fonts and rich text.

local textService = game:GetService('TextService')

local label = path.to.label
local scrollingFrame = label.Parent

local textBoundsParams = Instance.new('GetTextBoundsParams')
textBoundsParams.Font = label.FontFace
textBoundsParams.Size = label.TextSize
textBoundsParams.RichText = label.RichText
textBoundsParams.Width = label.Parent.AbsoluteSize.X
textBoundsParams.Text = label.Text

local ok, size = pcall(textService.GetTextBoundsAsync, textService, textBoundsParams)

if ok then
	scrollingFrame.CanvasSize = UDim2.new(1, 0, 0, size.Y + 1) -- unsure if you need one pixel for padding on this method but I would add it to be safe
else
	warn('Failed to get text bounds because', size)
	
	scrollingFrame.CanvasSize = UDim2.new(1, 0, 0, label.TextSize * 30) -- some arbitrary size if this method fails
end
local Players = game:GetService("Players")
local scrollingFrame = script.Parent
local textLabel = scrollingFrame.TextLabel
local localPlayer = Players.LocalPlayer
local playerGui = localPlayer.PlayerGui
local shopGui = playerGui:WaitForChild("Shop")
local shopPanel = shopGui:WaitForChild("ShopPanel")
local SelectedItem = require(shopPanel.ActiveSelection)
local TextService = game:GetService("TextService")


local function resetDescription()
	if not SelectedItem.CurrentItem then -- if no selection is made or an item is deselected
		scrollingFrame.TextLabel.Text = "No item is selected..."
		return
	end
	
	local item = SelectedItem.CurrentItem
	
	local name = item.Name or "Unnamed item"
	local price = item.Price or "???"
	local description = item.Description or "Uh, there's no description for this item, sorry!"
	
	scrollingFrame.TextLabel.Text = description
	
	local descriptionSize = TextService:GetTextSize(description, textLabel.TextSize, textLabel.Font, Vector2.new(textLabel.Size.Width, math.huge))
	print(descriptionSize)
	
	scrollingFrame.TextLabel.Size = UDim2.new(1,0, 0,descriptionSize.Y)
end



shopGui.Events.NewSelection.Event:Connect(function()
	resetDescription()
end)

I tried this but it keeps coming out to “(some number), 32” which is the TextSize of the TextLabel. I don’t know why it’s getting stuck at one line of text even when I’m telling it to assume there’s infinite Y space. I’m genuinely lost as to what to do now

Apparently this works??? Somehow??? I thought that the pcall(textService.GetTextBoundsAsync... thing would require a function call or something but that just ended up breaking it, tried it again exactly as you wrote and it started magically working. Could you please explain how that works?

It is still doing the function call, the pcall just calls the function with the arguments and catches errors instead of you calling it yourself.

pcall(textService.GetTextBoundsAsync, textService, textBoundsParams)

textService.GetTextBoundsAsync is the reference to the function we want to call
textService is the first argument (we pass this manually, when calling a function with a colon it implicitly passes whatever is before the colon as the first argument but in this case we have to pass it explicitly as we aren’t calling the function with a colon)
textBoundsParams is the second argument

1 Like

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