LayoutUtil: Automatically sizes a ScrollingFrame's UIGridLayout/UIListLayout

The ScrollingFrame should be set to a CanvasSize of (0, 0, 0, 0). With that you should be setting all the children to scale from inside studio, there should be no offset.

Appreciate the fix, it works great! This is exactly the behavior I’ve been looking for. I would appreciate one favor though. If you could tell me how I can remove that horizontal scrolling bar, then this would be perfect.

Can’t say I’m sure how this would help. I am a bit of a UI amateur.

Think I found a stack overflow bug.

When LayoutUtil is run on a UIListLayout with no sibling frames to apply its listing characteristics to, adding frames will work fine up until the scrollbar has to be created to view them all.

Here’s a gif of the module working fine, as it was run on a UIListLayout with 1 sibling frame.
https://gyazo.com/68dc330ed0de4e0e0373d1d4ec44a825

Here’s a gif of the module breaking because the module was run when the UIListLayout had no sibling frames. You can see the game freeze and become unresponsive as I copy the last frame that would’ve created the scrollbar. The frame never appears in the gif because stack overflow occurred before it could be rendered.
https://gyazo.com/128054e9ecd5ddb3aef0931cc4d1dd64

If you need more information or want a copy of the .rbxl to reproduce the bug, I can provide it.

Appears I was using an old version of the module, disregard the above.

Yep, it should all be good on the latest release. Also regarding the UIAspectRatioConstraints, I recommend using this plugin which has a button to automatically create the constraint and set the ratio. Not only that, but it has options to convert the UI to scale or offset (should be scale). I would definitely do some research on the constraints if you aren’t familiar because it’s very important when it comes to UI designing.

1 Like

Just started using this library in my game and I’m loving how easy it is to setup. The only issue is I’m getting mixed results when it comes to dealing with the ScrollingFrames. In all of my ScrollingFrames I have a UIGridLayout and a UIAspectRatioConstraint parented to it. In my inventory menu, it works correctly, but in my other ScrollingFrames it extends the scrolling out to the right instead of vertical. I can’t imagine why, because scrolling for those frames has always been vertical. Is there something I’m forgetting?

Is this necessary anymore now that we have AutomaticSize?

My library does two things, it resizes the canvas and it resizes the children. The new automatic size feature I’m hoping to integrate once it’s released, but all that should do is change the canvas size.

Now let’s say you have a UIGridLayout and the CellSize is in offset. As shown in the first gif without LayoutUtil, you could see how it only shows 1 column of UI elements once the resolution was lowered. Let’s say you have the CellSize in scale, every time the canvas resizes it will stretch out the children. Which is all undesired behavior that is solved with my library.

LayoutUtil also has the added benefit of calculating the CellPadding/Padding and resizing the children of a UIListLayout/UIGridLayout.

Hmm, in the latest update I fixed a small bug which extended the ScrollingFrame horizontally even though it was vertical. Are you sure the ScrollingDirection of the ScrollingFrame isn’t mistakenly set to only the X axis? If this issue still persists, hmu in my dms and we can get it sorted.

Whenever I try to use it, the Scrolling Frame just glitches rapidly. And the canvassize is like -294382923-

Are you sure you avoided the bad mistakes provided in the documentation.

I cannot make a custom chat with this, I need to scale the text label thing depending on the size of text but weird things happen can someone help me? I mean the calculate text size thing outputs the size as offset which is not responsive and you said we need to use scale for the elements(i mean if its scale it automatically sizes everything anyway so whats the point of this module)

well in the second paragraph if i understand it correctly cant we do the same thing to every gui instance like put the module on replicated first require it and it will handle everything every gui instance make everything responsive so it scales well into mobile and pc’s without anything else just one line

Would’ve saved me a lot of time organizing UIGridLayout’s and such, thanks for the amazing release!

I’m not exactly sure what you’re asking me. But as described in the gifs provided, you could see the effect of using my module and not using it. Now in the comparison gif I showed a game that used offset for the CellSize. Rather if they used Scale it would end up stretching each element and making it look ten times worse. Fortunately my library solves both of those problems, but when you first create the ScrollingFrame and UIGridLayout it’s required to be done in scale. Also unless if it’s happening on immediate start of opening the game, you should be storing this in a place other then ReplicatedFirst (preferably somewhere only accessible by the client).

I am aware that you can’t change the size of an element inside of a ScrollingFrame while LayoutUtil is active, this is a feature that I’m hoping to include in the next update.

I found a bug. If there is a UIPadding within the scrolling frame and there are a lot of children, it creates huge space at the top

A lot of children:
image

Fewer children:
image

EDIT: It also makes it so you can’t see the bottom row properly
image

After testing it myself, UIPadding inside a ScrollingFrame has weird behavior. It seems to me like you meant to parent the UIPadding to the parent of the ScrollingFrame.

LayoutUtil v1.0.0

The largest update yet following a complete rewrite of the codebase and documentation. Not only that, but there is now complete typescript support for use with roblox-ts. Recently, I was looking back at the code lately, wondering what is this for? Why did I add this? I included a ton of redundant features that were totally confusing or completely useless. This is a big reason for a complete remake.

For the contents of this update, I’ve fully integrated Luau type checking. Although this feature is still in beta (you might notice a lot of orange highlighted source code), if used properly it should make LayoutUtil a breeze. When linking a new UILayout, to ensure proper type checking, follow the short guide below.

local class: LayoutUtil.List = LayoutUtil.new(script.Parent.ScrollingFrame) -- considering theres a UIListLayout inside

It’s as simple as adding a colon followed by LayoutUtil.List for a UIListLayout, or LayoutUtil.Grid for a UIGridLayout.

That’s it? Nahhhh, I’ve implemented a variety of methods including:

  • .new(layout: UIListLayout | UIGridLayout, noStartup: boolean) - The noStartup parameter is new, replacing the configuration table. This parameter determines if it will immediately start resizing everything (otherwise call :Play() to start).

  • :UpdatePadding() - Updates the padding manually if it’s paused

  • :UpdateSize() - Updates the children size or CellSize manually if it’s paused.

  • :UpdateCanvas() - Updates the canvas manually if it’s paused.

  • :Update() - Calls the three functions above.

  • :Play() - Plays it so that it automatically updates.

  • :Pause() - Pauses it.

  • :Destroy() - Destroys the class

And a couple of read-only properties:

  • .Ref: UIGridLayout | UIListLayout - A reference to the UILayout.

  • .Paused: boolean - Whether or not it’s paused.

  • .Destroyed: boolean - Whether or not it’s destroyed.

And a couple of interchangeable properties:

  • DoUpdatePadding: boolean - Whether or not to update the padding.

  • DoUpdateSize: boolean - Whether or not to update the children’s size or CellSize.

  • DoUpdateCanvas: boolean - Whether or not to update the CanvasSize of the ScrollingFrame.

Unfortunately, you will have to alter your code to work with the latest API if you have previously used the “advanced” functionality. For the better, this was done. If you have imported LayoutUtil directly from the Roblox catalog, there is no need to worry, for this version I have created a new asset (which I suggest to integrate).

Before version 1.0.0 you had to use methods like :SetDefault(), which was actually the only method that only allowed you to change the default padding (and CellSize for UIGridLayouts). In the latest version you are able to directly change the properties of a UIGridLayout/UIListLayout including Padding, CellSize, CellPadding, and the size of any child within a UIListLayout. LayoutUtil automatically adapts to those changes and retains the aspect ratio around that size.

There were a few bugs located and squashed, unfortunately, I forgot to record all of them. There was a strange behavior that prevented it from working while adjusting the FillDirection during runtime.

I intended on adding a feature to automatically ignore the CanvasSize on startup, but after careful consideration, there would be too many minor exceptions. For example, let’s say you have a template that you clone into the ScrollingFrame and it’s supposed to be relative to the size of the canvas from startup, the slot would end up compressing. I understand that having to resize the canvas after you had everything perfectly sized is frustrating, but that’s where my new plugin comes to play.

Introducing LayoutUtilPlugin

The plugin to end the clash between scale and offset. It contains a total of five buttons:

  • Scale - Converts the selected GuiObject to scale.

  • Offset - Converts the selected GuiObject to offset.

  • RatioConstraint - Inserts a UIAspectRatioConstraint into the selected objects, automatically calculating the AspectRatio.

  • Remove Canvas - Sets the CanvasSize to all zeros while maintaining the size of each child, which makes LayoutUtil happy.

  • Import - Imports the latest version of LayoutUtil into the StarterGui.

A few key features include:

  • The ability to convert UIGridLayouts, UIListLayouts, UIPaddings, UICorners, UIPageLayouts, and UITableLayouts to scale or offset.

  • Selecting a ScreenGui (or BillboardGui, SurfaceGui, &, etc) will convert every descendant.

  • Converting elements in a ScrollingFrame will make sure it’s size stays consistent.

  • Automatically converts the CanvasSize to scale (which shouldn’t be too important for LayoutUtil).

  • Utilizes ChangeHistoryService so you could easily revert changes.

  • Removing the CanvasSize from a ScrollingFrame will keep the size of each child (accounts for UIGridLayouts).

  • A lot of edge cases are checked, being if the parent is a type of Gui it will use the screen size, otherwise if it’s not a GuiObject it won’t resize. If the property is being affected by the X or Y axis (ex: FillDirection & more in-depth ones).

Hopefully, this plugin should make working with UI in general seamless.

If there are any questions, feature requests, or bugs, please be sure to let me know. The best way to get in contact is via Discord, but I actively read DevForum DMs.

Roblox - iiNemo
Discord - nickk#9163

Documentation | Repository | Releases | Roblox Library | Plugin

5 Likes

Thanks for this fantastic contribution, will be very useful!

Awesome plugin. Is there a way to automatically add a little bit of canvas size on the bottom in case some of your contents get cut off?
https://gyazo.com/f5bd03f96789ccae0b8f11397cc53fce
As you can see in this GIF, it cuts off the scrolling frame right when the contents end which can look a little bit awkward in some cases, especially when there is padding on top.

Interesting situation, but unfortunately there is currently no way to add CanvasSize padding. You could fix this problem by having a container frame with a ScrollingFrame inside, but I could see how that is inconvenient and doesn’t have the exact same behavior. I’m actually planning on revamping the library and approaching it from a whole new angle which should solve issues such as this one.

2 Likes