Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Force Immediate Layout Update

Discussion in 'UGUI & TextMesh Pro' started by kromenak, Dec 8, 2015.

  1. dimzki

    dimzki

    Joined:
    Apr 17, 2018
    Posts:
    12
    This works on my case (Unity 2021.3.10f1)

    Code (CSharp):
    1. IEnumerator RefreshUI()
    2.     {
    3.         yield return new WaitForEndOfFrame();
    4.      
    5.         _horizontalLayoutGroup.SetLayoutHorizontal();
    6.         LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_horizontalLayoutGroup.transform);
    7.     }
     
  2. grrava

    grrava

    Joined:
    Nov 11, 2012
    Posts:
    46
    Chiming in, this is the only thing that worked for me (tried all the above solutions and others):

    Code (CSharp):
    1. private IEnumerator ForceUpdateLayout(Component panel)
    2. {
    3.     var layoutgroup = panel.GetComponentInChildren<LayoutGroup>();
    4.     if (layoutgroup != null)
    5.     {
    6.         yield return null;
    7.         layoutgroup.enabled = false;
    8.         layoutgroup.enabled = true;
    9.     }
    10. }
    It's baffling that this is still such an issue in a product that exists for years... (Unity 2021.3.11f1)
     
  3. LexaMV

    LexaMV

    Joined:
    Feb 20, 2018
    Posts:
    28
    this is the only thing that worked for me
     
  4. ianfan53

    ianfan53

    Joined:
    Jun 22, 2023
    Posts:
    1
    I encountered the same problem. I rebuilt the UI layout without using any Content Size Fitter components following Gresolio's suggestions and it now works perfectly. I highly recommend using Layout Elements to achieve the auto-sizing and responsive layout goal.
     
    sandolkakos likes this.
  5. JegoBestaatal

    JegoBestaatal

    Joined:
    Jun 30, 2020
    Posts:
    1
    Real life saver here, finally got my layout groups doing what they're supposed to be doing. Don't get why this is still such a problem, given the amount of people having issues with it.
     
  6. Joakim

    Joakim

    Joined:
    Dec 18, 2012
    Posts:
    5
    Thank you very much sir, this worked for me. Documentation is misleading to this day and should be updated.
    Just a note for anyone using this, you will probably want to prefetch all RectTransforms to optimize this.
     
  7. Fressbrett

    Fressbrett

    Joined:
    Apr 11, 2018
    Posts:
    97

    This works! I have used your approach to write a couple of extension functions. In some scripts I want to rebuild the same LayoutGroup multiple times, thus I added a function that returns the retrieved child LayoutGroups as an array, so that for the next repaint the expensive
    GetComponentsInChildren
    can be avoided by directly calling refreshes on the elements of the cached
    LayoutGroup[]
    array. The Refreshing of layout Groups now also avoids all
    GetComponent<RectTransform>()
    calls. All in all, this should be more performant:
    Code (CSharp):
    1. /// <summary>
    2. /// Rebuilds a layout group (and its children). Use this instead of Canvas.ForceUpdateCanvases() to immediately update a layout group.
    3. /// This function returns all layout groups that were updated, which can be used to refresh them again without having to gather all child layout groups another time.
    4. /// </summary>
    5. public static LayoutGroup[] FindAndRebuildLayoutGroupsImmediate(this LayoutGroup rootLayoutGroup)
    6. {
    7.     LayoutGroup[] layoutGroups = rootLayoutGroup.GetComponentsInChildren<LayoutGroup>();
    8.     RebuildLayoutGroupsImmediate(layoutGroups);
    9.     return layoutGroups;
    10. }
    11.  
    12. /// <summary>
    13. /// Rebuilds all layout groups within an array.
    14. /// Use it with the array returned by FindAndRebuildLayoutGroupsImmediate() to perform multiple updates of the same set of layout groups.
    15. /// </summary>
    16. public static void RebuildLayoutGroupsImmediate(this LayoutGroup[] layoutGroups)
    17. {
    18.     foreach (var layoutGroup in layoutGroups)
    19.     {
    20.         LayoutRebuilder.ForceRebuildLayoutImmediate(layoutGroup.transform as RectTransform);
    21.     }
    22. }

    This is how I use them:
    Code (CSharp):
    1. LayoutGroup[] refreshedGroups = _myVertLayoutGroup.FindAndRebuildLayoutGroupsImmediate();
    2. // do something here that requires us to repaint again
    3. refreshedGroups.RebuildLayoutGroupsImmediate();
    4. // do something else here that requires us to repaint again
    5. refreshedGroups.RebuildLayoutGroupsImmediate();
    Don't forget to call
    FindAndRebuildLayoutGroupsImmediate()
    again when you add/delete layout groups within the children of the root LayoutGroup during runtime!

    Of course you can also just ignore the returned LayoutGroup[] array in case you don't want to rebuild the same layout later on and just care about a single rebuild:
    Code (CSharp):
    1. _myVertLayoutGroup.FindAndRebuildLayoutGroupsImmediate();
     
    Last edited: Dec 17, 2023
    sandolkakos likes this.