Search Unity

TMP_InputField /_Text not rebuilding initially

Discussion in 'UGUI & TextMesh Pro' started by Julien_at_work, Aug 5, 2019.

  1. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    Hi,
    When updating TMP_InputField.text right after instantiation of a containing prefab, the display of the underlying TMP_Text is not built or updated properly (empty/invisible).
    The editor-inspector shows the correct value in the input field, meaning the value passed through script arrives there, only the scene part is faulty.
    I can trigger a rebuild manually, by toggling for example boldness on and off. After that the value displays; so it must be something related to setting the value right after instantiation.
    Here are the relevant parts of the script that access the TMP_Input, Setup is called right after instantiation, 'input' is the TMP_InputField reference:

    Code (CSharp):
    1.  
    2. ...
    3. public override void Setup(string labelText, RangeFloat? limits, float? initialValue)
    4. {
    5.    SetLabelText(labelText);
    6.    input.characterValidation = TMP_InputField.CharacterValidation.Decimal;
    7.    input.onValueChanged.RemoveListener(OnValueChanged);
    8.    if (limits.HasValue)
    9.    {
    10.        this.limits = limits.Value;
    11.    }
    12.    if (initialValue.HasValue) SetValue(initialValue.Value);
    13.    input.onValueChanged.AddListener(OnValueChanged);
    14. }
    15.  
    16. float GetValue()
    17. {
    18.    float.TryParse(input.text, NumberStyles.Float, CultureInfo.InvariantCulture, out var val);
    19.    return val;
    20. }
    21.  
    22. public override void SetValue(float value)
    23. {
    24.    if (useLimits) limits.ClampValue(ref value);
    25.    var val = value.ToString("0.0", CultureInfo.InvariantCulture);
    26.    input.text = val;
    27. }
    28. ...
    29.  
    Is there something i'm missing?
     
  2. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    Unfortunately this ugly modification makes it work:
    Code (csharp):
    1.  
    2. public override void Setup(string labelText, RangeFloat? limits, float? initialValue)
    3. {
    4.    SetLabelText(labelText);
    5.    input.characterValidation = TMP_InputField.CharacterValidation.Decimal;
    6.    input.onValueChanged.RemoveListener(OnValueChanged);
    7.    if (limits.HasValue)
    8.    {
    9.        this.limits = limits.Value;
    10.    }
    11.    valueToSet = initialValue;
    12.    Invoke(nameof(DelayedSet), Time.deltaTime);
    13. }
    14.  
    15. float? valueToSet;
    16. void DelayedSet()
    17. {
    18.    if (valueToSet.HasValue) SetValue(valueToSet.Value);
    19.    input.onValueChanged.AddListener(OnValueChanged);
    20. }
    21.  
    And more robust if replaced with a delay value that guarantees to skip atleast that one apparrently needed frame
     
  3. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
  4. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    That's unfortunate.
     
  5. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    After instantiation and changing / setting the text, have you tried calling ForceLabelUpdate()?
     
  6. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    I tried that and a forced Canvas update, that didn't seem to improve it. But i think it was while the object was still disabled. I'll try to see if it makes a difference if enabled.
     
  7. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    If you can't seem to resolve the issue, please provide me with a simple repro project that I can take a look at.
     
  8. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    I'm now experiencing this again (i had to put the last project aside so i wasn't able to dig deeper).
    This time i tried to create a reproduction scene, but in a newly created setup it works as expected (see attachment, which atleast illustrates parts of the structure of the real project). But now the issues is that it affects the layout, meaning the text doesn't stretch its container by itself.
    Even putting this into Start():

    Code (CSharp):
    1. LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
    2. LayoutRebuilder.MarkLayoutForRebuild(transform.parent as RectTransform);
    3. inputField.ForceLabelUpdate();
    4. LayoutRebuilder.ForceRebuildLayoutImmediate(transform as RectTransform);
    5. LayoutRebuilder.ForceRebuildLayoutImmediate(transform.parent as RectTransform);
    6. Canvas.ForceUpdateCanvases();
    does not update the layout (it's as if those calls are just ignored), which impresses me greatly.
    A workaround though is setting the .text property to "" and to the previous value again in Start() (Which i want to avoid for complexity and callback reasons)
    The original project is way too complex and big to submit via the bug reporter unfortunately, but hopefully this behaviour can provide some kind of hint atleast.
    Edit: here is what it looks like (just clicking on some layout option re-adjusts/fixes it):
     

    Attached Files:

    Last edited: Feb 7, 2020
  9. Julien_at_work

    Julien_at_work

    Joined:
    Aug 9, 2018
    Posts:
    35
    Ok, i actually just found a workaround, calling inputField.textComponent.ForceMeshUpdate(true) right after setting the value fixes it, not sure why it's needed though.