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:
...
public override void Setup(string labelText, RangeFloat? limits, float? initialValue)
{
SetLabelText(labelText);
input.characterValidation = TMP_InputField.CharacterValidation.Decimal;
input.onValueChanged.RemoveListener(OnValueChanged);
if (limits.HasValue)
{
this.limits = limits.Value;
}
if (initialValue.HasValue) SetValue(initialValue.Value);
input.onValueChanged.AddListener(OnValueChanged);
}
float GetValue()
{
float.TryParse(input.text, NumberStyles.Float, CultureInfo.InvariantCulture, out var val);
return val;
}
public override void SetValue(float value)
{
if (useLimits) limits.ClampValue(ref value);
var val = value.ToString("0.0", CultureInfo.InvariantCulture);
input.text = val;
}
...
Is there something i’m missing?
Unfortunately this ugly modification makes it work:
public override void Setup(string labelText, RangeFloat? limits, float? initialValue)
{
SetLabelText(labelText);
input.characterValidation = TMP_InputField.CharacterValidation.Decimal;
input.onValueChanged.RemoveListener(OnValueChanged);
if (limits.HasValue)
{
this.limits = limits.Value;
}
valueToSet = initialValue;
Invoke(nameof(DelayedSet), Time.deltaTime);
}
float? valueToSet;
void DelayedSet()
{
if (valueToSet.HasValue) SetValue(valueToSet.Value);
input.onValueChanged.AddListener(OnValueChanged);
}
And more robust if replaced with a delay value that guarantees to skip atleast that one apparrently needed frame
After instantiation and changing / setting the text, have you tried calling ForceLabelUpdate()?
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.
If you can’t seem to resolve the issue, please provide me with a simple repro project that I can take a look at.
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():
LayoutRebuilder.MarkLayoutForRebuild(transform as RectTransform);
LayoutRebuilder.MarkLayoutForRebuild(transform.parent as RectTransform);
inputField.ForceLabelUpdate();
LayoutRebuilder.ForceRebuildLayoutImmediate(transform as RectTransform);
LayoutRebuilder.ForceRebuildLayoutImmediate(transform.parent as RectTransform);
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):
w9buf
5454372–556848–StructureExample.zip (1.23 MB)
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.