Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

TextMesh Pro consistent set Autosize across multiple text fields

Discussion in 'UGUI & TextMesh Pro' started by Grumpy-Dot, Jan 17, 2019.

  1. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    Hello,

    I am wondering if anyone has an idea how to implement a simple solution to sync the font size for multiple text components from TextMesh Pro if they have Autosize set up.
    The end text size should be the minimum Autosize font dimension of all components.

    This was already partially done for a simple old UnityEngine.UI.Text component here: https://answers.unity.com/questions/1002091/how-do-i-calculate-a-text-size-with-the-best-fit-o.html
    but it's incomplete and it's not working dynamically in the editor.

    What would be ideal in my opinion is for each TextMeshPro UGUI component to have an additional field for a Text Group (similar with the Toggle and Toggle Group). Based on that reference all the text components will be synced up and update each other's size.

    I will start working on this, let me know if you would like this feature and you want to see the end result, or if you have any suggestions on how to implement it.
     
    skabed, latrodektus and _TheFuture_ like this.
  2. Hosnkobf

    Hosnkobf

    Joined:
    Aug 23, 2016
    Posts:
    1,096
    Good Idea. I totally see the use case.

    I would suggest that you do not make it like the toggle group but the reverse way: Instead of assigning the "Text Group" to the Text component, you assign the Text component to a list inside the "Text Group". This way you do not need to change or derive from the TextMeshPro class.

    So, the "Text Group" holds a list of text items. It also should contain relevant settings like min size / max size which is automatically applied to all items in the list on start up to be sure they can all be treated equally. Ideally this settings are automatically set when the first item is assigned to the group.
    Of course this "Text Group" component also takes care of all the rest of the logic, like finding the smallest size and apply it to to every item (auto size should then be turned of, I guess).
     
    Weasel and Grumpy-Dot like this.
  3. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    @Hosnkobf Thanks for the reply!
    Yes that would be an easy method to implement it, and it was this way in the link I provided.
    It has the advantage of being easy to implement and not having to change the TextMeshPro class.

    The only reason I wanted to work in a similar way as the ToggleGroup is that I wanted for this to be compatible with one of my own UI scripts. This script is responsible to dynamically clone a template (either a prefab or an existing ui element) to a specified number of times, and manage the cloned elements.
    Say you have a list of toggles or a list of level buttons in a scrollable list.
    This ElementCloner class would take a template and duplicate it dynamically and provide a list of the cloned elements that can be easily parsed and individually customized.
    This work perfectly with the ToggleGroup approach, each Text component has a field for the TextGroup, and will keep the same reference when it's duplicated, so no extra work is necessary.

    If I go the way you suggested, then I have to parse the cloned elements one extra time to get the text components and add them to the list of the "Text Group". This is not hard to do, but I would prefer to avoid it.

    Let me know if you understood my specific case, if you are interested, I can provide the script in question to make it more clear.

    Thanks again for you feedback. PS: I love the Better UI plugin ;).
     
  4. Hosnkobf

    Hosnkobf

    Joined:
    Aug 23, 2016
    Posts:
    1,096
    I totally understand.

    Let me start from the bottom:
    I am happy that you love Better UI :)
    For Better UI I made a decision with a huge impact: I derived my "Better" components from the normal UGUI / TextMesh Pro components. This opens up a lot of possibilities: I could actually modify the internal logic of the class to a degree which wouldn't be possible to do from outside. Also, I just can replace the normal component and relink any references to the better component without problem. But it also has a downside: If somebody else uses a derivation of one of these "normal" components he cannot use better ui or change the base class to the "Better" class pendant.

    So, if you now start to make a derivation of TextMeshPro and want to use Better UI but also want to share it with people who don't use Better UI, you need to make two versions of it...

    For you, I would suggest to implement it as a separate component which requires the TextMeshPro component. Something like "Text Group Item". For me, I will consider adding this feature to the BetterTextMeshProUGUI component since I already derive from it.
     
    Grumpy-Dot likes this.
  5. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Just poking my head-in here for a few seconds.

    For performance reasons, make sure auto-sizing is disabled on all objects except the one being tested. In theory, you should only have to test auto-size on the longest text string as it would result in the smallest point size. Then this component would simply set this optimum point size on all other text objects in the group.
     
    Grumpy-Dot likes this.
  6. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    Yes, I agree, that is a good improvement suggestion. Unfortunately this will not work in all cases, you may have a long text, but with a large RectTransform, so the resulting font size might be quite large for the rest of the text components.

    What do you think about setting the auto-sizing for all text components but only for a few frames, then disabling it once the font size calculation is done? And do this update only if the text values change?
     
  7. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    I totally agree with your suggestions. But I also need to somehow call a Refresh method if the text value of that TextMeshPro component changes. I think I am forced to override TextMeshPro for this, as there is no callback for it.

    I look forward to see this feature in Better UI if you plan to introduce it.
     
  8. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I think worst case scenario would be have to test each text component once to find this optimum point size but then this component should then set this optimum size on all text objects in the group and disable auto-size on all of them.
     
  9. Muuurphy

    Muuurphy

    Joined:
    Sep 22, 2013
    Posts:
    4
    @Grumpy-Dot Did you ever get around to implementing this?
     
  10. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    Yes, unfortunately I can't share the code but basically I have a SizeUniformizer class that has a public list of TextMeshProUGUI components.
    In the update I compare the text values with an internal list of strings to check if they have changed (or if the texts are visible, etc), and recompute the minimum size.
    The minimum text size is computed by parsing each active TextMeshProUGUI, setting fontSizeMin and fontSizeMax to some reasonable limits, setting enableAutoSizing to true, then calling the Rebuild(CanvasUpdate.PreRender) method on them.
    This will update the fontSize property to the best fit value, use that to get the global minimum best fit value.
    Then parse them again, set enableAutoSizing to false and fontSize to the minimum best fit value.

    Sorry if this is unclear, let me know if you manage to implement it.
     
    Palineto and _TheFuture_ like this.
  11. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    See the following post including some sample script. Hopefully this proves useful to you.
     
    skabed and _TheFuture_ like this.