Search Unity

VisualElements won't grow to fill space for some reason

Discussion in 'UI Toolkit' started by mikevargas, Oct 12, 2019.

  1. mikevargas

    mikevargas

    Joined:
    Aug 17, 2019
    Posts:
    22
    (First of all, yes, I've read all the documentation and flex-box reference multiple times.)

    I have two empty, plain VisualElement objects. Their parent is a simple container VisualElement with display:flex and flex-direction:column. In other words, I just want to stack two VisualElements on top of each other and have them fill all available space.

    I've set the flex-grow of the child VisualElements each to 1 and the flex-shrink of each to 0. These elements are contained within a custom EditorWindow which contains no other elements, i.e. it's:

    rootVisualContainer
    parentFlexContainer (VisualElement, flex-direction:column)
    flexItem1 (VisualElement, flex-grow:1, flex-shrink:0, width/height:auto)
    flexItem2 (VisualElement, flex-grow:1, flex-shrink:0, width/height:auto)


    The width and height of flexItem1 and 2 are 'auto'.

    Everything I understand about flex layout tells me that, given this hierarchy, flexItem1 and flexItem2 should fill the EditorWindow in such a way that they each take up half the vertical space of the window, i.e. the bounds should look like:

    visualelementlayouts.png

    But they don't. Instead, they don't take up any space whatsoever, despite their flex-grow properties and width/height set to auto.

    Is this a bug, or am I fundamentally misunderstanding flex layout?
     
  2. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    It may be an issue with the parent not having any height. So on your parent style use this:

    Code (CSharp):
    1. .stretch {
    2.     position-type: absolute;
    3.     position-left: 0;
    4.     position-top: 0;
    5.     position-right: 0;
    6.     position-bottom: 0;
    7. }
    8.  
    9. <VisualElement class="parent-container stretch">
    10.     <VisualElement class="child1"></VisualElement>
    11.     <VisualElement class="child2"></VisualElement>
    12. </VisualElement>
    Or just add the stretch styles into the parent css.

    I always use that to make the equivalent of the HTML 'body' tag.

    'display: flex', 'flex-direction: column' on the parent and 'flex-grow: 1' on both children should be enough. Remove all other settings such as width/height/shrink.

    If it doesn't work, try adding 'align-items: stretch' and 'align-content: stretch' on the parent too.
     
  3. mikevargas

    mikevargas

    Joined:
    Aug 17, 2019
    Posts:
    22
    Somehow that worked, thank you. Unfortunately I was using this to try to resolve a more specific issue, which doesn't seem to be remedied by it. Specifically, all I am trying to do is get an Image to align to the top of the EditorWindow. This image scales uniformly as the window is resized, which is ideal, but for some reason I can't get the actual Image to be placed at the top of the window. Further, the bounds of the Image's VisualElement don't seem to be the same as the bounds of the image and that seems to be what causes the problem.

    My original thinking was that I could place the Image as the top VisualElement in a flex container and put some spacer VisualElement below it, which, when setting flexGrow to 1 on the bottom element, should push the Image up to the top if the Image had a flexGrow of 0 and a flexShrink of 1. No luck, though.

    Anyway, this sounds like a sufficiently different issue that I may make a new question for it. I really appreciate your help as this is another issue I have faced in many forms.
     
  4. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    Are you using an Image tag or using background-image CSS? Using background-image should keep it inside.
     
  5. mikevargas

    mikevargas

    Joined:
    Aug 17, 2019
    Posts:
    22
    I'm doing this all in code, and the image URL will regularly change so I couldn't hard-code it in CSS (er, USS).
     
  6. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Your parentFlexContainer should also have flex-grow: 1. The children are trying to take up all available space, but the parent will have 0 height. This is because of the default align styles of the rootVisualElement.
     
  7. MoruganKodi

    MoruganKodi

    Joined:
    Feb 11, 2015
    Posts:
    79
    Not sure If I should make a seperate post, but I am getting inconsistent behaviour between UIBuilder and my actual Editor Windows, which seems to be a bug related to the above question.

    UIBuilder shows my correct flexbox setup, of a two column layout.

    Parent is set to grow, both nested columns are set to grow.
    Left coolumn has a list, also set to grow.

    In UIBuilder it shows correctly.
    In the editor window however nothing grows vertically to fit the window.

    What it looks like in UIBuilder:


    What it actually looks like:



    Now when I look inside UIElementsDebugger, unity creates an unnamed "TemplateContainer" between my elements and the actual root container from my loaded UXML, which does not have grow on it, but we cannot set any properties on our actual root node (aka the "Heirarchy" is the root node in UIBuilder).

    This template container shrinks on it's own, and my elements inside it are trying to grow to it.
    How do we work around it? How do we grow the template container?

     
  8. MoruganKodi

    MoruganKodi

    Joined:
    Feb 11, 2015
    Posts:
    79
    Ok found a workaround.

    TemplateElement comes from `VisualElement uxml = visualTree.CloneTree();`

    So instead of doing `root.add(uxml);` which includes that TemplateConatiner, I had to iterate the children inside them and add only the children, as such:

    Code (CSharp):
    1.  
    2. VisualElement uxml = visualTree.CloneTree();
    3. for(var i = 0; i < uxml.childCount; i++)
    4. {
    5.       root.Add(uxml.ElementAt(i));
    6. }
    7.  
    Which bypasses the TemplateContainer root, and thus Flex-Grow now works.
     
    kassskata likes this.
  9. MoruganKodi

    MoruganKodi

    Joined:
    Feb 11, 2015
    Posts:
    79
    Erm. I discovered now that root.add also removes elements from the TemplateContainer (why? Bug or nonstandard behaviour?),

    so the actual workaround had to be implemented like this:

    Code (CSharp):
    1.  
    2.  
    3. VisualElement uxml = visualTree.CloneTree();
    4. while(uxml.childCount > 0)
    5. {
    6.     root.Add(uxml.ElementAt(0));
    7. }
     
  10. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    I had the same issue a while ago. I asked why they couldn't just remove it - https://forum.unity.com/threads/why...r-flex-grow-1-by-default.613324/#post-4119280

    They just need an option to not create one, or a better system to make cloned root elements instantiate in the correct place (like your solution, if I understand the reason for TemplateContainer existing correctly), or at least make it auto-expand its height.

    I ended up making my entire app without using UXML at all because of this stuff. Just made everything in C# using MVC pattern, but you obviously want to use the new editor.
     
  11. uMathieu

    uMathieu

    Unity Technologies

    Joined:
    Jun 6, 2017
    Posts:
    398
    You can pass the element container to visualTree.CloneTree(root). This will create elements and add them without the creation of a TemplateContainer
     
    Demexis, OMGeeky, tjumma and 3 others like this.
  12. MagicDesignEmerick

    MagicDesignEmerick

    Joined:
    Oct 4, 2017
    Posts:
    26
    This is not really clear reading the documentation. Especially since the example showed uses the setup creating the templatecontainer : https://docs.unity3d.com/2020.1/Documentation/Manual/UIE-LoadingUXMLcsharp.html (the example also doesn't compile, btw)
     
  13. aklgupta

    aklgupta

    Joined:
    Jun 9, 2014
    Posts:
    29
    I had a very similar issue to what everyone here is discussing.
    In my case, the root element in UXMl/UI Builder was set to flex and grow to take up the whole editor window, however it didn't work in the actual editor window.
    Turned out that when the UXML is loaded into the editor using
    root.Add(UXML)
    or
    UXML.CloneTree(root)
    (or similar methods), all it's children are actually populated into a new
    VisualElement
    sometimes called "TemplateConatiner".
    This "TemplateConatiner" is not set to grow (
    flexGrow
    ). Just changing
    flexGrow
    style property for this element to the desired value is enough to replicate the behavior seen in the UI Builder editor window.
     
    Pecek likes this.
  14. Alexander_V

    Alexander_V

    Joined:
    Feb 26, 2020
    Posts:
    8
    If your instantiation code is like this:
    Code (CSharp):
    1. root.Add(uxml.ElementAt(i));
    Just add style to USS:
    Code (JavaScript):
    1. :root {
    2.     flex-grow: 1;
    3.     height: 100%;
    4.     width: 100%;
    5. }
     
    S_Pugh likes this.
  15. unity_3D1F2458AB75386BB89A

    unity_3D1F2458AB75386BB89A

    Joined:
    Aug 16, 2022
    Posts:
    12
    It's crazy that this is not a default logic, and that it is not documented anywhere that example showed in Unity documentation creates additional element under the hood

    Still happens, by the way, took me several hours to figure why my layout is different in editor and in window
     
    dnorambu and Syncadius like this.