Search Unity

Unity UI How is Image preferred size determined?

Discussion in 'UGUI & TextMesh Pro' started by Ghant, Sep 8, 2019.

  1. Ghant

    Ghant

    Joined:
    Aug 22, 2019
    Posts:
    8
    I have a panel, and I want its preferred width to match the size of its child objects, which are Text components, but the background Image is overriding the preferred width with a large value (1000x1000). How is the Image preferred size determined? Is there a way I can override it or give preference to the Vertical Layout Group?

    image.png
     
    Last edited: Sep 8, 2019
  2. Chris128

    Chris128

    Joined:
    May 15, 2013
    Posts:
    12
    I spent hours trying to make this work in a project recently... no idea why this is so insanely intuitive and weird to get something so simple working. But anyway I eventually ended up with this:

    To start with I have a Canvas which has a Vertical Layout Group component added to it with the options "Control child size (both Width and Height)" enabled, and everything else disabled.

    Within that Canvas there is a Panel with an Image component added to it set to whatever image you want, but also a Vertical Layout Group component with all options disabled.

    Then within the Panel there is my text object (which is TextMeshPro but presumably this works the same with default UI text) and on that I have a Content Size Fitter component with both options set to Preferred Size.

    If you only want it to resize to width rather than height, you'll have to mess about with things and none of it will behave how you think it will -_-

    EDIT: Actually ignore that. Just to add to the ongoing ridiculousness, it turns out that only works fine in the scene view and game view, but not when I actually run the time. Amazing.
     
    Last edited: Sep 15, 2019
    theCodeHermit likes this.
  3. Chris128

    Chris128

    Joined:
    May 15, 2013
    Posts:
    12
    OK this is by far the most confusing and frustrating part of Unity I've come across. The fact that the resizing and position behaviour in scene view and game view frequently does not match what happens when you run the game is very annoying. Also at one point the behaviour changed when I disabled one of the vertical layout group options so I enabled the option straight away again and the behaviour would not go back to how it was!

    ANYWAY... this is what I've got that works now. Who knows when it might decide to just behave differently for no reason though.

    • Canvas (root object) has Vertical Layout Group component on it with every option disabled
    • Panel (child of Canvas) has the Image component on it and also a Vertical Layout Group with all options disabled, as well as a Content Size Fitter with both options set to Min Size
    • Text (child of Panel) has a Content Size Fitter on it with both options set to Preferred Size.
    So yeah that results in my image resizing to both the width and height of the text.
     
    theCodeHermit likes this.
  4. Ghant

    Ghant

    Joined:
    Aug 22, 2019
    Posts:
    8
    Created the following script to prefer layout groups over image dimensions. Maybe this can help you.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3. using UnityEngine.UI;
    4.  
    5. [RequireComponent(typeof(HorizontalOrVerticalLayoutGroup))]
    6. [RequireComponent(typeof(RectTransform))]
    7. public class PreferLayoutGroup : UIBehaviour, ILayoutElement
    8. {
    9.     public float minWidth
    10.     {
    11.         get
    12.         {
    13.             return GetLayoutGroup().minWidth;
    14.         }
    15.     }
    16.  
    17.     public float preferredWidth
    18.     {
    19.         get
    20.         {
    21.             return GetLayoutGroup().preferredWidth;
    22.         }
    23.     }
    24.  
    25.     public float flexibleWidth
    26.     {
    27.         get
    28.         {
    29.             return GetLayoutGroup().flexibleWidth;
    30.         }
    31.     }
    32.  
    33.     public float minHeight
    34.     {
    35.         get
    36.         {
    37.             return GetLayoutGroup().minHeight;
    38.         }
    39.     }
    40.  
    41.     public float preferredHeight
    42.     {
    43.         get
    44.         {
    45.             return GetLayoutGroup().preferredHeight;
    46.         }
    47.     }
    48.  
    49.     public float flexibleHeight
    50.     {
    51.         get
    52.         {
    53.             return GetLayoutGroup().preferredHeight;
    54.         }
    55.     }
    56.  
    57.     public int layoutPriority
    58.     {
    59.         get
    60.         {
    61.             return 100;
    62.         }
    63.     }
    64.  
    65.     ILayoutElement layoutGroup;
    66.  
    67.     public void CalculateLayoutInputHorizontal()
    68.     {
    69.     }
    70.  
    71.     public void CalculateLayoutInputVertical()
    72.     {
    73.     }
    74.  
    75.     protected override void OnEnable()
    76.     {
    77.         base.OnEnable();
    78.         LayoutRebuilder.MarkLayoutForRebuild(GetComponent<RectTransform>());
    79.     }
    80.  
    81.     protected override void OnDisable()
    82.     {
    83.         LayoutRebuilder.MarkLayoutForRebuild(GetComponent<RectTransform>());
    84.         base.OnDisable();
    85.     }
    86.  
    87.     ILayoutElement GetLayoutGroup()
    88.     {
    89.         if (layoutGroup == null)
    90.         {
    91.             layoutGroup = GetComponent<HorizontalOrVerticalLayoutGroup>();
    92.         }
    93.         return layoutGroup;
    94.     }
    95. }
    96.  
     
  5. Dusan_Dimitriev

    Dusan_Dimitriev

    Joined:
    Aug 25, 2019
    Posts:
    1
    Hey man, thanks for the answer, and the script... can't believe that this is the only post I found regarding this problem :S
     
  6. Guozf

    Guozf

    Joined:
    Apr 14, 2020
    Posts:
    1
    thank u very much !!! you saved me
     
  7. Benji_1996

    Benji_1996

    Joined:
    Jul 9, 2018
    Posts:
    1
    It's funny finding this two years after the fact, really needed this info, thanks!
     
  8. HenryChinaski

    HenryChinaski

    Joined:
    Jul 9, 2013
    Posts:
    108
    Your Script solved all my issues. Thanks!!!
     
  9. Stephanommg

    Stephanommg

    Joined:
    Aug 18, 2014
    Posts:
    88
    First I want to thank you for the code, it helped me!
    Second, I want to inform a bug in it. The function flexibleHeight should return GetLayoutGroup().flexibleHeight and not GetLayoutGroup().preferredHeight.
     
  10. ncboman

    ncboman

    Joined:
    Jun 13, 2015
    Posts:
    1
    I ran into this too and I believe this has to do with the borders on the sprite metadata. in the screenshots I posted, my sprite's top/bottom borders are each 26, and the preferred height is 52. I suppose this is optimized for nine boxed sprites.
     

    Attached Files:

    Rafael-Dolfe likes this.
  11. theforgot3n1

    theforgot3n1

    Joined:
    Sep 26, 2018
    Posts:
    205
    This worked excellently! Great work and thank you.
     
  12. aelkman

    aelkman

    Joined:
    Jun 27, 2015
    Posts:
    2
    Came here with the same problem, stuck for over an hour and pulling my hair out why the Preferred Size on the Content Size Fitter was forcing a size larger than the child text elements. Using your script immediately fixed it. You're a gem, sir. Thank you.

    Why Unity behaves the way it does in many UI cases.... I am just baffled. It needs to be fixed badly.
     
  13. Rafael-Dolfe

    Rafael-Dolfe

    Joined:
    Nov 20, 2023
    Posts:
    4
    Ran into the exact same thing. Sliced are also problematic in how they compete for preferred width/height.