gilzoide / unity-flex-ui

Flexbox layout support for Unity UI using the Yoga layout engine
The Unlicense
96 stars 5 forks source link

Properly integrate `FlexLayout` into UGUI #27

Open RichardWepnerPD opened 1 month ago

RichardWepnerPD commented 1 month ago

UGUI has certain ways how it does things, and some are not yet considered by FlexLayout or done differently. The problem of this is that it's either unintuitive to use or just unusable in some scenarios.

Aspects that should be supported:

The FlexLayout can already be used in the current state, however it seems like it can only be used on the top level or with another FlexLayout as parent. This prevents it to be used within a ScrollRect or within layout groups e.g. if you want to transition slowly from UGUI layouts to FlexLayout where its useful.

gilzoide commented 1 month ago

Hey @RichardWepnerPD, thanks for the report.

Short answer

I think your issue is valid, and we should add a new component FlexLayoutGroup that is actually an ILayoutGroup and applies the flex layout in all children RectTransforms as you expect, without removing the current implementation.

Long answer:

So, currently FlexLayout being a separate layout system for UGUI, you need to actually add FlexLayout to all nodes that you want layed out using flexbox. This way, you have to opt-in to using flex, instead of it driving all of your RectTransforms and you needing to opt-out with ILayoutIgnorer instead. Of course, this is a debatable design, there are pros and cons for both approaches. I'm really sorry if it wasn't clear in the README in that you need FlexLayout in children for it to work.

Aspects that should be supported:

  • ILayoutElement properties (see #26)

FlexLayout/Yoga already support minimum/maximum/flexible sizes, the only thing missing is preferred size, which I think should be addressed by measure functions (as discussed in #24). In case we start laying out all children RectTransforms with flex, we'll certainly take ILayoutElement into consideration.

Children of a layout element should be layed out unless they are configured to be ignored (see ILayoutIgnorer) currently, children need to be marked with a FlexLayout or they are ignored i.e. the opposite

This is about what I said in the begining, "the opposite" is actually the current design of things. The thing is: every object needs a YGNode attached for Yoga to actually lay it out. There will be times where you'll want to tweak margin/padding for a leaf node and you'll need a FlexLayout component, but won't want to affect its children, so you'd have to add ILayoutIgnorer to all of them. Also implementing a FlexLayout that creates and tracks YGNodes for all its children is quite more complex than the current implementation, although it is surely doable.

On the other hand, I guess most people will want to go with flex all the way and expect that adding a FlexLayout will lay out everything below it, like you are asking here.

Maybe we could have both things, and actually create a new component, something like FlexLayoutGroup, that is actually an ILayoutGroup and does what most UGUI users would expect. Then the current implementation could be renamed to FlexLayoutNode or FlexNode or something like that and keep its existing behaviour, what do you think? This would be a nice way to avoid compatibility breaks as well.

properties controlled by layout elements should be "marked" as such (you can observe this with the ContentSizeFitter, *LayoutGroup, etc.)

FlexLayout already does this, but it only drives children that also have FlexLayout components.

however it seems like it can only be used on the top level or with another FlexLayout as parent

Yes, this is the current design of it, mostly the "with another FlexLayout as parent", as discussed above.

This prevents it to be used within a ScrollRect

ScrollRects already do the right thing when you have a FlexLayout on the Content root with auto width or height depending on horizontal vs vertical scroll, as long as its children also have FlexLayouts to be layed out by it. You can check this out in the ScrollView sample scene.