Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Content size fitter refresh problem

Discussion in 'Unity UI (uGUI) & TextMesh Pro' started by drHogan, Oct 3, 2017.

  1. drHogan


    Sep 26, 2012
    Hi guys,

    I am fixing an old tooltip system of mine, and I am going nuts on an apparently fairly simple issue. What it should to, is basically that the tooltip size should adapt to the text size. (the movement, not going out of screen, etc etc is all implemented and working)

    This is my tooltip

    The root is an empty object with the script, going down one we find the "container" that has a canvas, a canvas group and moves around (i could probably skip this one and bring it to the root) :

    Then ContentLayout is the one with Content Size Fitter and Horizontal Layout :

    And Tooltip Text is a simple TextMeshPro UI element of text.

    Now, the problem is, the whole system works, but not as it should. I.e. if I move my mouse pointer over an element, i get a tooltip with correct text, but resized according to the previous element hovered (so if I hover and leave and hover again a button, i get the correct size for that button because of having hovered it twice).

    This is a sample of what happens for example (the tooltip before was smaller)

    I guess the problem is that I have no idea on how to force an immediate refresh of the content size fitter. I tried deactivating it and re-activating it, i tried to wait for the end of frame with a co-routine before making it visible, etc etc. But the problem remains.

    Any hints on what i might tackle to solve it?

  2. FunRobDev


    Jun 3, 2017
    Hi there. I had a very similar setup for tooltips with the same issue. This solved my problem:

    Code (CSharp):
    1. tooltTipText = "new tooltip \n second row";
    2. Canvas.ForceUpdateCanvases();  // *
    3. tooltTipText.transform.parent.GetComponent<HorizontalLayoutGroup>().enabled = false; // **
    4. tooltTipText.transform.parent.GetComponent<HorizontalLayoutGroup>().enabled = true;
    * According to documentation, a canvas (which controls your UI elements) performs its layout and content generation calculations at the end of a frame, just before rendering, in order to ensure that it's based on all the latest changes that may have happened during that frame. Code that relies on up-to-date layout or content can call Canvas.ForceUpdateCanvasaes() to ensure it before executing code that relies on it.

    ** Sometimes the reenabling of the HorizontalLayoutGroup or VercticalLayoutGroup is also needed, but it depends on your configuration.

    Cheers :)
    Last edited: Apr 3, 2018
    fenghou and ramkaentertainment like this.
  3. ramkaentertainment


    Sep 23, 2018

    I had created a start menu for my VR game using vertical and horizontal layout group functionalities and the content size fitter component to arrange the buttons automatically.

    After my Unity update from version 2018.2.8f1 to version 2018.3.0f2, my box collider of the buttons didn't work anymore. I calculate the box collider sizes via script in the start method, depending on the rect transform of the according buttons.
    I found out, that the box collider sizes were zero.

    With Unity 2018.2.8f1 the content size fitter has calculated the rect transform before the start method is called.
    With Unity 2018.3.0f2 the content size fitter calculates the rect transform obviously after the start method is called.

    Calling Canvas.ForceUpdateCanvasaes() before I calculate the size of the box collider in the start method worked for me too.

  4. Cloppi


    Sep 16, 2015
    @FunRobDev ,
    Thank you! Your approach with additional re-enabling of HorizontalLayoutGroup component helped me to solve the problem as well. I've got an array of similar UI elements with dependence to Text.text.Lenght and they didn't want to placing correctly in the parent panel, but re-enabling replaced them right way.

  5. doctorpangloss


    Feb 20, 2013
    This is a little wonky, you probably don't want to just disable/enable/ForceUpdateCanvases because it'll give UGUI people a heart attack. Implement `ILayoutElement` on your tooltip script, and in your CalculateLayoutInputHorizontal implementation, call CalculateLayoutInputHorizontal on the child. Also, implement preferredWidth using the child text's preferredWidth. Attach a content size fitter. That's it.
    unity_KNMBKAJDXv98xw likes this.
  6. dadude123


    Feb 26, 2014

    costs a ton of cpu cycles for no reason.
    Use LayoutRebuilder.ForceRebuildLayoutImmediate instead.
    You can pass in the transform for which you want to do the refresh.

    When using it with content size fitter you might want to call it twice with the same object in some situations (when you have a contentsizefitter + layout control at the same time).

    Calling that method twice will still be 100x faster than forcing a full refresh of the whole canvas.
    losingisfun and doctorpangloss like this.
  7. losingisfun


    May 26, 2016
    Have to agree with dadude123 on this. However, should clarify you will need the RectTransform of the content size fitter / layout component. Simply cache this and you'll have it working much quicker.

    I would HIGHLY recommend that you do not use GetComponent, rather cache the reference, because a GetComponent call is ridiculously expensive.