UnityRef is currently in early development. Some features may be incomplete and/or not functioning.

UNITYREF

Your Pit Stop For Solving ANYTHING in Unity

ui

[UI Toolkit] Fix TextElement Font Scaling Anomalies

Solution

ui toolkitbuild optimizationserializationvfx graphtext rendering

Unity 2021.3.x - Unity 6.3.x

Published Sat, Mar 7

Issue

 When the scale of a FontAsset is modified during runtime, existing TextElement components do not automatically refresh to display the updated scaling. Standard methods like MarkDirtyRepaint() prove ineffective for propagating these specific changes because the internal uitkTextHandle remains in a cached state.

Quick-Fix

Modifying a FontAsset scale requires forcing an internal refresh of the uitkTextHandle via reflection to ensure the text mesh is properly rebuilt.

Expand Analysis

To ensure TextElements reflect changes made to a FontAsset scale at runtime, a direct approach leveraging reflection is necessary for Unity versions where direct methods are not exposed. This involves explicitly marking your text element as dirty for both repaint and layout changes, and then specifically setting the internal uitkTextHandle to dirty. This two-pronged approach ensures that the Unity UI Toolkit re-evaluates and redraws the text with the new font properties.

  1. Use reflection to access the IncrementVersion method of VisualElement to notify the system of visual changes.
  2. Trigger a refresh by combining VersionChangeType.Repaint and VersionChangeType.Layout flags.
  3. Retrieve the internal uitkTextHandle from your text element instance.
  4. Invoke the SetDirty method on the uitkTextHandle to force the underlying text generator to rebuild the mesh.

The utility method provided uses reflection to access internal VisualElement and TextElement methods. First, IncrementVersion is invoked on your text element with VersionChangeType.Repaint | VersionChangeType.Layout to signal that both visual and layout aspects require an update. Subsequently, the internal uitkTextHandle property is accessed and its SetDirty method is invoked. This combination forces a comprehensive refresh of the text rendering pipeline.

Additional Tips

  • Runtime modifications to font assets affect all elements using that asset; use this method sparingly to avoid performance spikes during layout passes.
  • Ensure your project includes the UnityEngine.UIElements namespace for access to VersionChangeType and TextElement types.
  • If your text still fails to refresh after calling this method, consider re-assigning the text property to your text element to trigger a standard string update pass.

Copy


using System.Reflection;
using UnityEngine.UIElements;

public static class UIUtil
{
    public static void MarkDirtyText(this TextElement textElement)
    {
        if (textElement == null) return;

        // Access the internal versioning system of VisualElement
        MethodInfo incrementVersion = typeof(VisualElement).GetMethod("IncrementVersion", 
            BindingFlags.NonPublic | BindingFlags.Instance);

        // Notify both Repaint and Layout version changes
        incrementVersion?.Invoke(textElement, new object[] { (long)(VersionChangeType.Repaint | VersionChangeType.Layout) });

        // Access the internal handle property
        PropertyInfo handleProperty = typeof(TextElement).GetProperty("uitkTextHandle", 
            BindingFlags.NonPublic | BindingFlags.Instance);

        object uitkTextHandle = handleProperty?.GetValue(textElement);

        if (uitkTextHandle != null)
        {
            // Force the specific text handle to mark itself as dirty
            MethodInfo setDirty = uitkTextHandle.GetType().GetMethod("SetDirty", 
                BindingFlags.Public | BindingFlags.Instance);
            setDirty?.Invoke(uitkTextHandle, null);
        }
    }
}

Related Posts Haven't quite found a solution to your problem? We think these posts might help you.

Content inspired by a Unity discussion post.