Search code examples
c#unity-game-engineuser-interface

Text Mesh Pro - Auto Size plus Content Size Fitter


So I have a button with text in it. I am updating the text via script. Some of the buttons have more text than others so I set it up with Auto size. But even then sometimes the text doesn't fit the button so I want the button to grow to fit the text.

The issue is that with a Vertical Layout Group and Content Size fitter. The TMP_Text grows and so does the button but it grows at the max font size (even with auto-size on) Ideally I want it to only grow once it has shrunk to the smallest possible size.

I have tried so many different possibilities with Vertical Layout group and layout elements and content size fitters but I am completely at a loss as to how to get it to do what I want.

enter image description here This is what I want (this is in the editor not run time and it works)

enter image description here This is also in the editor

enter image description here This is what I get

I noticed also that this happens with spaces. If I have one word with no spaces in between it seems to scale properly.

Edit: So I guess how would I go about getting auto-size to work with space?


Solution

  • Setup:

    ┓ Container
    ┗┳ Button
    ... ┗ TMP_Text

    Both Container and all Buttons have VerticalLayoutGroup with "Control Child Size" and ContentSizeFitter with "VerticalFit" set to "Preferred Size"


    Problem:

    The Preferred Height of a TMP_Text with "autoSize" is based on the maximum Font and not the minimum Font.


    Solution:

    You will have to override the preferred height with an LayoutElement. The following MonoBehaviour-Class controls an LayoutElement that should be added to each TMP_Text:

    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    [RequireComponent(typeof(TMP_Text))]
    [RequireComponent(typeof(LayoutElement))]
    [ExecuteInEditMode]
    public class PreferMinSize : MonoBehaviour
    {
        TMP_Text tmp;
        LayoutElement layout;
        [SerializeField, Tooltip("Minimum height of the text")] float minHeight = 50;
    
        private void OnEnable()
        {
            tmp = GetComponent<TMP_Text>();
            layout = GetComponent<LayoutElement>();
    
            tmp.OnPreRenderText -= OnTextChanged; // prevent adding multiple times
            tmp.OnPreRenderText += OnTextChanged;
    
            OnTextChanged(tmp.textInfo);
        }
        private void OnTextChanged(TMP_TextInfo info)
        {
            if (!this.enabled)
                return;
    
            if (tmp.enableAutoSizing == false)
                return;
    
            // get minimum height needed for min font size
            tmp.enableAutoSizing = false;
            tmp.fontSize = tmp.fontSizeMin;
            // set height of min font, but with a capped min size
            layout.preferredHeight = Mathf.Max(tmp.preferredHeight, minHeight);
            // restore behaviour
            tmp.enableAutoSizing = true;
        }
        private void OnDisable()
        {
            tmp.OnPreRenderText -= OnTextChanged;
        }
    }
    

    After adding this component to your button-texts you can set the "minHeight" parameter to set the minimum Height and the text will shrink to its minimum font size to fill the minimum Height and only after that it will expand the text.

    Demo: enter image description here enter image description here