You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity运行时修改TMPro样式表中字体大小标签的方案

运行时修改TMPro样式表中的字体大小

我已经配置好了TMPro样式表,里面用<size=23px>这类标签设置字体大小。现在想在运行时修改这些大小(逐个修改也可以),用来实现游戏UI设置里的字体大小滑块,理想情况是把每个字体大小都乘以一个系数。

补充:我是通过样式表的起始标签设置大小的,希望运行时更新样式表的设置,而不是直接修改TextMeshProUGUI组件的文本大小!

我能直接引用默认的styleSheet,用GetStyle通过名称或哈希码获取对应的TMP_Style,但拿到TMP_Style后可操作的东西有限。查文档发现可以读取styleOpeningDefinition属性来获取起始标签,我能从中提取并替换<size="50px">里的数值,但这个属性是只读的,没法重新赋值。我的代码如下:

TMP_Text text = GetComponent<TMP_Text>();
TMP_Style style = styleSheet.GetStyle("H1");
openingTags = style.styleOpeningDefinition;
 
string[] size = openingTags.Split("px><cspace=");
string _splitString = size[0].Replace("<size=", "");
float _currentSize = float.Parse(_splitString);
_currentSize *= multiplier;
 
string _newTags = "<size=" + _currentSize + "px>" + size[1];
 
style.styleOpeningDefinition = _newTags;   // 报错:Property or indexer 'TMP_Style.styleOpeningDefinition' cannot be assigned to -- it is read only
style.RefreshStyle();

解决方案

因为styleOpeningDefinition是只读属性,我们可以通过反射修改私有字段或者创建新样式替换原有样式来实现需求:

方法1:反射修改私有字段

TMP_Style内部对应styleOpeningDefinition的私有字段是m_StyleOpeningDefinition,通过反射修改它后,刷新样式和文本组件即可生效:

using System.Reflection;
using TMPro;
using UnityEngine;

public class TMPStyleSizeAdjuster : MonoBehaviour
{
    public TMP_StyleSheet styleSheet;
    public float sizeMultiplier = 1.2f;

    public void AdjustStyleSizes()
    {
        // 获取目标样式(以H1为例)
        TMP_Style targetStyle = styleSheet.GetStyle("H1");
        if (targetStyle == null) return;

        // 解析原起始标签中的字体大小
        string originalTags = targetStyle.styleOpeningDefinition;
        string[] tagParts = originalTags.Split(new[] { "px><cspace=" }, System.StringSplitOptions.None);
        if (tagParts.Length < 2) return;

        if (!float.TryParse(tagParts[0].Replace("<size=", ""), out float originalSize)) return;
        float newSize = originalSize * sizeMultiplier;

        // 拼接新的起始标签
        string newOpeningTags = $"<size={newSize}px><cspace={tagParts[1]}";

        // 反射修改私有字段
        FieldInfo field = typeof(TMP_Style).GetField("m_StyleOpeningDefinition", BindingFlags.NonPublic | BindingFlags.Instance);
        if (field != null)
        {
            field.SetValue(targetStyle, newOpeningTags);
            targetStyle.RefreshStyle();
            // 刷新所有使用该样式表的文本组件
            RefreshAllTextInStyleSheet(styleSheet);
        }
    }

    void RefreshAllTextInStyleSheet(TMP_StyleSheet sheet)
    {
        foreach (TMP_Text text in FindObjectsOfType<TMP_Text>())
        {
            if (text.styleSheet == sheet)
            {
                text.ForceMeshUpdate();
            }
        }
    }
}

方法2:创建新样式替换原有样式

如果不想用反射,可以复制原有样式的所有属性,创建新样式后替换样式表中的旧样式:

using System.Reflection;
using TMPro;
using UnityEngine;

public class TMPStyleSizeAdjuster : MonoBehaviour
{
    public TMP_StyleSheet styleSheet;
    public float sizeMultiplier = 1.2f;

    public void AdjustStyleSizes()
    {
        TMP_Style originalStyle = styleSheet.GetStyle("H1");
        if (originalStyle == null) return;

        // 解析并计算新字体大小
        string originalTags = originalStyle.styleOpeningDefinition;
        string[] tagParts = originalTags.Split(new[] { "px><cspace=" }, System.StringSplitOptions.None);
        if (tagParts.Length < 2) return;

        if (!float.TryParse(tagParts[0].Replace("<size=", ""), out float originalSize)) return;
        float newSize = originalSize * sizeMultiplier;
        string newOpeningTags = $"<size={newSize}px><cspace={tagParts[1]}";

        // 创建新样式并复制原有属性
        TMP_Style newStyle = new TMP_Style();
        newStyle.name = originalStyle.name;
        newStyle.hash = originalStyle.hash;
        newStyle.styleClosingDefinition = originalStyle.styleClosingDefinition;

        // 反射设置起始标签(因为公共属性只读)
        FieldInfo field = typeof(TMP_Style).GetField("m_StyleOpeningDefinition", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(newStyle, newOpeningTags);

        // 替换样式表中的旧样式
        styleSheet.ReplaceStyle(originalStyle, newStyle);
        RefreshAllTextInStyleSheet(styleSheet);
    }

    void RefreshAllTextInStyleSheet(TMP_StyleSheet sheet)
    {
        foreach (TMP_Text text in FindObjectsOfType<TMP_Text>())
        {
            if (text.styleSheet == sheet)
            {
                text.ForceMeshUpdate();
            }
        }
    }
}

注意事项

  • 反射操作可能会随TMPro版本更新失效,如果后续官方开放了可写API,建议改用官方方案。
  • 修改样式表后必须调用ForceMeshUpdate()刷新所有关联文本,才能看到变化。
  • 批量修改多个样式时,遍历styleSheet.styles列表逐个处理即可。

内容的提问来源于stack exchange,提问作者The Embraced One

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:41:30