Unity脚本修改TextMeshProUGUI文本值的实现方法
Unity 无法修改TextMeshProUGUI文本值问题排查
问题背景
- 开发玩家资料菜单填充功能时,模板对象下挂载有Image组件、Text (TMP) 子对象
- 通过
GameObject.FindGameObjectsWithTag查找所有带指定标签的模板对象,在循环中尝试将Json读取到的玩家数据赋值给对应文本,但始终无法修改TMP文本的显示值 - Unity版本更新前,相同逻辑可正常修改原生UGUI Text组件内容,更新后TMP组件赋值无效
- 经调试确认循环中可获取到
TextMeshProUGUI类型对象,Json读取模块功能正常
问题原代码
using UnityEngine; using UnityEngine.UI; using TMPro; public class JSONReader : MonoBehaviour { public TextAsset textJSON; public PlayerList myPlayerList = new PlayerList(); public GameObject playerTemplate; public readonly string playerTemplateTag = "playerTemplate"; //Player Model [System.Serializable] public class Player { public int id; public string name; public string imageLink; } //Array of Influencers [System.Serializable] public class PlayerList { public Player[] player; } // Start is called before the first frame update void Start() { myPlayerList = JsonUtility.FromJson<PlayerList>(textJSON.text); PopulatePlayerSelect(); } private void PopulatePlayerSelect() { var buttonGameObjects = GameObject.FindGameObjectsWithTag(playerTemplateTag); foreach(GameObject playerTemplate in buttonGameObjects) { var image = playerTemplate.GetComponentsInChildren<Image>(); var name = playerTemplate.GetComponentsInChildren<TextMeshProUGUI>(); Debug.Log(name); } } }
问题原因
- 返回值类型理解错误:
GetComponentsInChildren<TextMeshProUGUI>()返回的是TextMeshProUGUI[]数组类型,不是单个TMP组件实例,直接对数组变量操作,根本没有访问到具体组件的.text属性,自然无法修改显示内容 - 缺少数据映射逻辑:遍历模板对象时,没有将模板和Json中对应索引的玩家数据做绑定,即使拿到组件也没有可赋值的数据源
- 组件查找逻辑不严谨:
GetComponentsInChildren会同时返回父物体挂载的同类型组件,如果模板自身挂了Image(比如按钮背景),会和头像Image混在同一个数组里,极易拿错组件;另外局部变量命名为name,和Unity内置的Object.name属性重名,容易引发逻辑混淆 - 不存在版本更新修改TMP文本属性名的情况,TMP组件的文本赋值属性一直是
.text,和原生UGUI Text一致
修复方案
- 优先用
transform.Find("子物体层级路径")精准定位名字文本、头像Image的所在对象,再获取对应组件,避免拿错 - 遍历模板时按索引匹配对应玩家数据,拿到单个TMP组件实例后,对其
.text属性赋值 - 增加长度校验,避免模板数量和玩家数据数量不匹配引发的数组越界问题
修复后的填充方法参考:
private void PopulatePlayerSelect() { var buttonGameObjects = GameObject.FindGameObjectsWithTag(playerTemplateTag); // 校验数据和模板数量匹配 if (buttonGameObjects.Length != myPlayerList.player.Length) { Debug.LogError($"模板数量与玩家数据数量不匹配,模板数:{buttonGameObjects.Length},玩家数:{myPlayerList.player.Length}"); return; } for (int i = 0; i < buttonGameObjects.Length; i++) { GameObject currentTemplate = buttonGameObjects[i]; Player currentData = myPlayerList.player[i]; // 替换括号内的路径为你自己项目中TMP文本、头像的实际子物体路径 TextMeshProUGUI playerNameText = currentTemplate.transform.Find("NameText").GetComponent<TextMeshProUGUI>(); Image playerAvatar = currentTemplate.transform.Find("AvatarIcon").GetComponent<Image>(); // 赋值文本 playerNameText.text = currentData.name; // 后续自行实现头像加载逻辑即可 } }
额外注意事项
- 明确类型的变量尽量不要用
var声明,尤其是组件查找的返回值,很容易因为隐式类型搞错对象结构 - 如果是动态生成列表的场景,建议把模板初始设置为隐藏状态,所有数据赋值完成后再显示,避免出现空白闪烁
- 不要用
GetComponentsInChildren不加筛选地拿子物体组件,尤其是层级复杂的UI对象,精准查找的稳定性远高于批量获取
内容的提问来源于stack exchange,提问作者MIM
相关产品推荐
相关产品推荐

