Flexible/dynamically sized grids (like HTML tables)?

I’ve tried the GridLayout and it seems to want to create uniformly-sized elements. But what I want is to be able to pass in a bunch of rows of elements and have it layout the contents like a table, resizing the columns based on the content.

My initial approach is to have a Panel with a Vertical Layout Group, containing several Row objects, each of which has a Horizontal Layout Group. Obviously this doesn’t create columns that are coherent across each row, so I need to find ways to iterate over the whole table to calculate column widths and row heights.

I tried making my own layout group, implementing SetLayoutVertical and SetLayoutHorizontal, and giving all the rows and cells a LayoutElement . It seems to work sporadically, but it emits many *"*Trying to add UnityEngine.UI.LayoutRebuilder for layout rebuild while we are already inside a layout rebuild loop. This is not supported." errors when I try and set a preferredWidth, and sometimes the LayoutElement component gets stuck with a Preferred Width of 143 and I can’t change it or uncheck it because the layout runs at edit time and the same errors interrupt the logic. It looks like editing a LayoutElement’s min/flexible/preferredWidth from within the layout functions is not the way to do things - so, what is?

…maybe I’m doing the wrong thing in trying to use LayoutGroups with LayoutElements? Should I just be trying to alter the RectTransforms directly? Ideally I only want to set the widths and heights and have the rest calculated for me, but maybe that’s not possible.

Once beta 18 is out (shouldn’t be too long now) the updated documentation will contain better and more detailed descriptions of how the auto-layout system works, which should make it easier to get started creating your own layout group. I suggest to wait for that, and then once you’ve read that, if you still have questions, ask away here.

Edit: Beta 18 is live now: Unity Editor Beta Releases

That was quick! The docs for Content Size Fitter still talk about audio though - someone’s been on the Copy and Paste. :wink: I’m not entirely sure what the Content Size Fitter actually does because the description makes it sound like it duplicates the anchor functionality.

UIAutoLayout.html does look to be updated, but it’s still a bit vague - it tells us what happens when the predefined components work, but doesn’t tell us how they do it, so I can’t work out how to override it. In particular I can’t see how to set a RectTransform’s width based on my own column width calculations. In particular, class-RectTransform.html claims there is a property called Width, but that’s not a property in the scripting API. I have no idea what I need to change on a RectTransform to alter an object’s width.

You change the anchoring of a RectTransform using anchorMin and anchorMax. The positioning can be controlled either with anchoredPosition + deltaSize (most intuitive when there’s no stretching) or with offsetMin and offsetMax (most intuitive when there is stretching). More more information, look up those properties in the scripting reference.

Thanks for the answer, but the anchoring stuff is pretty confusing even when I’m just drawing things in the editor, so I have no idea which incantations I would need to use to do what I want to do here. And it’s not clear whether these are things that respect the anchors, or whether it overrides them, etc.

Right now I can probably hack together what I need for my game by adding Layout Elements to every cell and setting the preferred size in each case, but I can’t help but think that there should be an easier way to dynamically resize a whole column based on its content without needing to manually recalculate every single cell’s new position and dimensions.

Have you read the pages “Basic Layout” and “Auto Layout” in the documentation bundled with beta 18? And about doing things from scripting, have you read the scripting reference docs for the various properties and methods in the RectTransform class? If you have and you have things you are still confused about, please ask away. Hopefully we can then make the documentation more clear.

Well sure, it would have been nice if we had had time to create a Table Layout Group to be included with the UI system, but unfortunately we didn’t. And without that component existing, it is a bit tricky. Table layout logic is not completely trivial.

Yeah, I read all the documentation I could find, but the problem is twofold:

  1. RectTransforms are complex. When you’re editing in the Inspector, you can just about work it out because it hides certain properties and exposes nice meta-properties (such as Width) to simplify things. When you have to do it all via script, you don’t get any of that. So the docs on the Basic Layout page are insufficient for understanding how to script it directly.

  2. It’s not clear what exactly a custom layout group overrides. Note that the Auto Layout documentation page makes no mention at all of anchors. My best guess is that anchors can be completely ignored by the system once it gets to this stage - after all, if you’re trying to position 2 things next to each other, their anchoring relative to the parent is potentially irrelevant. Or maybe a custom layout should respect vertical anchors when it’s just moving things horizontally, and vice versa. But if so, does this mean it needs to manually implement the anchor => position calculations itself? And if so, how? Or are these default values set up first before SetLayoutHorizontal/Vertical are called? The AutoLayout docs say that LayoutGroups control the sizes and positions of its child layout elements, but the algorithm makes no mention of how positions are calculated, only the sizes. And, going back to the ‘RectTransforms are complex’ bit, the Scripting reference for RectTransform keeps referring to setting values relative to anchors - but we’re past the anchor stage and I want to set an absolute position relative to a parent, and how to do that is not at all clear.

Hopefully you can see that it’s not clear exactly where the auto layout code or indeed any custom layout code ‘takes over’ from the default anchoring stuff, or how we would implement one of our own. I expect a small example would help a lot here.

Re: the Table Layout Group, I appreciate you don’t have time for everything and time is limited. It was more of a feature request, that’s all. The logic isn’t all that tricky when you have write access to the min and preferred widths during layout time, but we don’t have that under the current system.

1 Like

So, here’s a way to sort of do something like what you want.

Create an empty object, and put a VerticalLayoutGroup on it. Create a bunch of empty objects in that, and put HorizontalLayoutGroups on them. That gives you rows and columns. Now, put your stuff in there.

In order to force a size on a sub element, put a ContentSizeFitter (ignore the warning) set to Preferred, and a LayoutElement with the checkbox for Preferred Size. If you put the LayoutElement on there first before the LayoutGroups, the Preferred Size checkboxes default to the current size. Use empty object + CSF + LE to add padding to a row.

And you can mix and match rows as you like, so this is pretty good except it doesn’t support percentages and it doesn’t support ratios. Percentages will be trivial once the source is released just by editing the script, and ratios could be done sort of kludgy with percentages.

But yeah, that lets you do some table-like arrangements right now. Just remember to put both ContentSizeFitter and LayoutElement on Preferred on each element you want to lock to a size (and ignore the warning about not combining ContentSizeFitter and LayoutGroup).

I’ve been quite confused on the RectTransform properties, too. I’ve been trying to figure out how to convert from one RectTransform to another RectTransform. I want to move the anchoredPosition of one RectTransform to a particular spot on another RectTransform and have it work with scaling and anchors being at any location. The best I could find was to convert to a world point using TransformPoint then on the destination RectTransform use InverseTransformPoint, but that value doesn’t seem to account for the anchor at all. I have no idea how anchoredPosition is calculated. I want to set anchoredPosition to be in the spot that I have the world Vector3 for (and have the game object move with it), but the results of InverseTransformPoint isn’t always the correct value depending on what location the anchor is on.

@runevision some documentation on how the anchoredPosition is calculated would be nice. It just says it’s the position of the pivot relative to the anchor reference point, but there doesn’t seem to be a property to get the anchor reference point it’s referring to.

Yup, that’s the easy part. :wink:

This is interesting, thank you. But I still don’t understand exactly what the ContentSizeFitter is, because I know I can achieve a similar result here without one - ie. just by setting the min/preferred widths on the LayoutElement. And I can have one or more of them with a flexible size to fill the rest of the space too.

I guess this is the core of the issue - I can see a way to sort-of-solve my problem without the ContentSizeFitter, so it’s unclear what it does - but also, if a ContentSizeFitter doesn’t play nicely with a LayoutGroup, what does it actually do? What relevance does min size and preferred size have for a single element in isolation, since its size and stretching qualities are already evident when you place it on the canvas and set the anchors etc?

(Note to Unity people: I think the layout is an important area of the docs to focus on, because it’s not clear which components do what, and in which order.)

Setting min/preferred widths on the LayoutElement will not stop the LayoutGroups from stretching the elements. If you use ContentSizeFitter along with LayoutElement, you can prevent it from stretching so instead it will be centered in the cell.

ContentSizeFitter does a few things, but essentially: “Make me just big enough to fit all the stuff that’s inside me.”

Not in my experience - if you enter a Flexible [Height/Width] of zero, and set Min and Preferred to the same value, it will stay at exactly that size.

Well, I did try that, and it did not stretch, but it also stopped centering, because it had no flexible width to work with. Having CSF+LE to lock the Preferred size plus a flexible width >0 gave the the desired behaviour of not stretching while also distributing the free space.

Sure. Like I mentioned, to do things from scripting you’d need to read the scripting reference (not just the manual) for RectTransform and its various properties as well.

Yes, a LayoutGroup can set the anchors however it wants. It doesn’t make much difference when it has complete control over the position and size in any case. No matter where the anchors are, a given desired position and size can always be obtained when the position and size can be set freely and dynamically whenever the parent size changes.

So where the anchors should be for a child controlled by a layout group is “undefined” since it doesn’t matter anyway, except for the internal calculations of that layout group.

The built-in layout groups normally set the anchors to the top left corner. From there on you can specify size using sizeDelta and position either by using anchoredPosition (this needs to take the pivot into account) or by using offsetMin and offsetMax. You can look up those in the scripting reference for more info.

I’ve tried to explain all this clearly on the page about Auto Layout in the UI Overview section of the Manual. It was heavily revised for beta 18 so if you only read it prior to that, please have a read again. If things are still unclear after reading that page, please ask away.

I have read the Scripting Reference for RectTransform. It’s not clear enough, yet. A common use case is going to be to set the width of an object - but the word ‘width’ doesn’t appear at all on ScriptReference/RectTransform.html. In fact that top group of variables is almost inpenetrable, in terms of what it all actually means. I appreciate that it is a window onto a very powerful anchoring system, but given that we know the anchors aren’t always relevant (as you say above), it’s very difficult to know how we are supposed to make changes when we are bypassing or ignoring anchors.

If I need to go revisit this (as I have given up on dynamic widths for now, and instead am just using fixed sized elements with one flexible element to use the rest of the space) I’ll give the sizeDelta and anchoredPosition stuff a shot, but I would love to see this clarified in a How To. An example of a custom layout group would be very useful.

“I’ve tried to explain all this clearly on the page about Auto Layout in the UI Overview section of the Manual.”

The ContentSizeFitter page has no Description at all (and the table of properties contains some clearly wrong text). And it is not mentioned on any of the other sub-pages in the Auto Layout section. It is covered in the UI How Tos section however, which is a good start.

From reading posts on here, I worked out that ContentSizeFitter is for when an element adjusts its own size based on its own content (sort of Bottom-Up sizing), and that LayoutGroups adjust their children’s sizes (sort of Top-Down sizing), and now I understand why they don’t really co-exist. But in the docs, this is sort of buried in that ‘How To’ page.

They can co-exist, though: They work fine together with no problems. In Editor mode it’s throwing some errors occasionally along with whatever the weird cross-barrier serialization pollution bug is, but when I actually Build And Run, it has no issues whatsoever. That “warning” is more of a “hey did you really mean to do that”.

I was referring to the page in the beta 18 manual that’s under UI > Overview > Auto Layout.

We know that not all pages are in a good state yet, which is why I specifically referred to a specific page that should be useful in the state it’s in in beta 18.

Sorry Rune, I missed the bit when you said ‘Overview’. It would be great if there were some extra links between the Overview and the Reference section!

1 Like