Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Snap VisualElement size

Discussion in 'UI Toolkit' started by Ghat-Smith, Nov 19, 2020.

  1. Ghat-Smith

    Ghat-Smith

    Joined:
    Aug 16, 2016
    Posts:
    48
    Hi.

    I have some VisualElements placed on a grid, and I would like to ensure the size of these visual elements are always a multiple of my grid size, and this multiple should be the closest one based on the size of the contents calculated size.

    Of course I could just override the width of my elements, but then if their contents change, the container size wouldn't adapt to the new closest grid size.

    Snapping elements positions to the grid is working. But I can't find a way to do the same thing for their size.
    Code (CSharp):
    1. public override void SetPosition(Rect newPos)
    2. {
    3.     newPos.position = newPos.position.RoundToNearest(10); // Position snap is working
    4.     newPos.size = newPos.size.RoundToNearest(10); // Size snap is not working
    5.     base.SetPosition(newPos);
    6. }
    7.  
    8. public static float RoundToNearest(this float value, float nearest) => (nearest == 0) ? value : (Mathf.Round((value / nearest)) * nearest);
    9. public static Vector2 RoundToNearest(this Vector2 value, float nearest) => new Vector2(value.x.RoundToNearest(nearest), value.y.RoundToNearest(nearest));
    How could I override the container width, without preventing contents size to expand in case of changes ?
    Or if I override container style width, is it possible to calculate the contents preferred width (so without container width constraint) ? This way I could update the container width based on the new closest multiple of grid size.
     
  2. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    Here's what I'd try:

    OuterContainer
    InnerContainer
    content

    Then
    1. let InnerContainer free to expand with its contents
    2. register for the GeometryChangeEvent on InnerContent to be notified when the content size changes
    3. in your GeometryChangeEvent, use the new size to set the size of the OuterContainer as a multiple of your grid size
     
  3. Ghat-Smith

    Ghat-Smith

    Joined:
    Aug 16, 2016
    Posts:
    48
    Thanks for the reply. I still didn't manage to get the expected result.

    How do you make InnerContainer ignore the width constraint of its parent ?
    In my case, if I reduce OuterContainer width, it will automatically reduce InnerContainer width.
    My elements use relative position. I tried to set overflow style to visible but same problem.

    When you say "set the size" do you mean overriding style width and height ? Or there is another way ?
     
  4. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,203
    You're right, this will be a problem. You might need to use Absolute position on the InnerContainer (just left at top/left:0). Then use InnerContainer.RegisterCallback<GeometryChangeEvent>(...) to detect its changes in size and adjust the OuterContainer's hard-coded: .style.width and .style.height

    I can't think of a different way to do this other then, yes, explicitly setting the width/height of your OuterContainer. Our flex properties don't provide for a way to say "only increments of 10px".
     
    Ghat-Smith likes this.
  5. Ghat-Smith

    Ghat-Smith

    Joined:
    Aug 16, 2016
    Posts:
    48
    I made the changes you suggested, but still can't get my expected result.
    I managed to snap the outer container size, but it creates an empty gap between InnerContainer size and OuterContainer size. In facts, after calculating the correct size, I would like the content to adapt to fill the new size. That happens if I set right:0px but then I'm coming back to the relative case scenario. InnerContainer would take the same size as OuterContainer, and if its content change, I wouldn't be able to detect if its size should be changed or not.

    upload_2020-11-24_21-33-6.png
    Screenshot to illustrate. Blue border is for the outer container which has been snapped to the grid.

    Maybe I could detect when InnerContainer has changed, remove the size constraint in the style (width in case of relative or right:0px in case of absolute), force a layout update (to get the new auto size values) and then set back the constraint based on the new auto size result ? Seems quite hacky, but would you have recommendations to do something like that ? Maybe a way to calculate auto size of a visual element (like I can do when using GUIStyle.CalcSize) ?