Search Unity

Resolved how to fix a position of an element to the bottom of a window?

Discussion in 'UI Toolkit' started by mengkaima, Aug 30, 2021.

  1. mengkaima

    mengkaima

    Joined:
    Apr 27, 2021
    Posts:
    8
    I want to place a button in the lower right corner of the window, and its position relative to the lower right corner shall not change with the size of the window. For instance:

    upload_2021-8-30_16-57-56.png

    The "next" button at the lower right. However, no matter how I set its parameters, it seems not responsive at all.

    I've tried to set the position to absolute, and set bottom and right to a fixed value, and adjusting the margin, but none of them worked. Can anyone help me?
     
  2. cpalma-unity

    cpalma-unity

    Unity Technologies

    Joined:
    Nov 30, 2020
    Posts:
    110
    Hello!

    Position absolute and a fix value for bottom and right should work fine. Here is an example of a footer and a button anchored to the bottom right.

    AnchoredButton.gif

    Code (xml):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    2.     <ui:VisualElement name="Content" style="flex-grow: 1;">
    3.         <ui:VisualElement name="Footer" style="position: absolute; bottom: 0; right: 0; left: 0; background-color: rgba(41, 41, 41, 255); height: 100px;">
    4.             <ui:Button text="Button" display-tooltip-when-elided="true" style="right: 10px; position: absolute; bottom: 10px;" />
    5.         </ui:VisualElement>
    6.     </ui:VisualElement>
    7. </ui:UXML>
     
  3. mengkaima

    mengkaima

    Joined:
    Apr 27, 2021
    Posts:
    8
    Hi there, many thanks!

    Actually I just figured out that the reason of my previous code's not working, which is because of the C# code behind.

    When you create a new editor window using UI Builder, some snippets will be generated automatically. However, they are not really "proper". The code is like:

    Code (CSharp):
    1. public class DemoWindow : EditorWindow
    2. {
    3.     [MenuItem("Window/UI Toolkit/DemoWindow")]
    4.     public static void ShowExample()
    5.     {
    6.         DemoWindow wnd = GetWindow<DemoWindow>();
    7.         wnd.titleContent = new GUIContent("DemoWindow");
    8.     }
    9.  
    10.     public void CreateGUI()
    11.     {
    12.         // Each editor window contains a root VisualElement object
    13.         VisualElement root = rootVisualElement;
    14.  
    15.         // VisualElements objects can contain other VisualElement following a tree hierarchy.
    16.         VisualElement label = new Label("Hello World! From C#");
    17.         root.Add(label);
    18.  
    19.         // Import UXML
    20.         var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/CustomWindows/DemoWindow.uxml");
    21.         VisualElement labelFromUXML = visualTree.Instantiate();
    22.         root.Add(labelFromUXML);
    23.     }
    24. }
    The thing is, the visual tree will be added to the root, or say, being a child of it, and then, there will be a root visual element whose size is auto. (This is just my personal understanding, it may not be right).

    To fix this problem, instead of instantiate a new visual element and add it to the root, actually we can clone the visual tree to the root, and then there will be no more additional parent visual element.

    Code (CSharp):
    1. var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Scripts/CustomWindows/DemoWindow.uxml");
    2. visualTree.CloneTree(rootVisualElement);
    I found the answer here: Making a listview fill space - Unity Forum
     
  4. cpalma-unity

    cpalma-unity

    Unity Technologies

    Joined:
    Nov 30, 2020
    Posts:
    110
    Yes! There is a difference between using
    Instantiate
    +
    Add
    and
    CloneTree
    . The first one will keep a root element (TemplateContainer) for the instantiated template and the second one will just instantiate the content of your template and add it directly to the provided root.

    Having a TemplateContainer might be useful in some cases since its C# class has some functions to know the source of the original template. When you use
    CloneTree
    you lose this extra information but you don't have the extra root element :)