Unity遍历列表时onClick.AddListener()失效,点击均触发最后一项数据
问题原因
循环中用闭包绑定按钮事件时,捕获的是变量i的引用,而非当前迭代的具体值。等所有按钮创建完成、循环结束后,i的值已经变成inventoryT1.Container.Count,此时点击任何按钮,i-1都会指向列表最后一项的索引,导致所有按钮都加载最后一个物品的数据。
解决办法
方法1:循环内创建局部变量保存当前物品/索引
在每次循环迭代中,把当前的物品对象或索引存入一个局部变量,让闭包捕获这个独立的变量,避免引用共享:
保存物品对象的写法
for (int i = 0; i < inventoryT1.Container.Count; i++) { // 保存当前迭代的物品对象 PrisonerObject currentPrisoner = inventoryT1.Container[i].item; GameObject obj = Instantiate(currentPrisoner.DefaultPrefab, Vector3.zero, Quaternion.identity, transform); obj.GetComponent<RectTransform>().localPosition = GetPosition(i); obj.GetComponentInChildren<TextMeshProUGUI>().text = inventoryT1.Container[i].level.ToString(); // 绑定事件时使用局部变量currentPrisoner obj.GetComponent<Button>().onClick.AddListener(() => LoadPrisonerStore(currentPrisoner)); }
保存索引的写法
for (int i = 0; i < inventoryT1.Container.Count; i++) { int currentIndex = i; GameObject obj = Instantiate(inventoryT1.Container[currentIndex].item.DefaultPrefab, Vector3.zero, Quaternion.identity, transform); obj.GetComponent<RectTransform>().localPosition = GetPosition(currentIndex); obj.GetComponentInChildren<TextMeshProUGUI>().text = inventoryT1.Container[currentIndex].level.ToString(); obj.GetComponent<Button>().onClick.AddListener(delegate { LoadPrisonerStore(inventoryT1.Container[currentIndex].item); }); }
方法2:给UI对象绑定自定义组件存储物品数据
如果想用ReturnObject(obj)的方式,可以给每个生成的UI对象添加一个自定义组件,用来存储对应的物品数据,后续通过组件获取:
步骤1:创建自定义组件
using UnityEngine; public class PrisonerItemUI : MonoBehaviour { public PrisonerObject prisonerData; // 存储当前UI对应的物品数据 }
步骤2:循环中赋值组件并绑定事件
for (int i = 0; i < inventoryT1.Container.Count; i++) { PrisonerObject currentPrisoner = inventoryT1.Container[i].item; GameObject obj = Instantiate(currentPrisoner.DefaultPrefab, Vector3.zero, Quaternion.identity, transform); obj.GetComponent<RectTransform>().localPosition = GetPosition(i); obj.GetComponentInChildren<TextMeshProUGUI>().text = inventoryT1.Container[i].level.ToString(); // 添加或获取自定义组件,存入物品数据 PrisonerItemUI itemUI = obj.GetComponent<PrisonerItemUI>(); if (itemUI == null) { itemUI = obj.AddComponent<PrisonerItemUI>(); } itemUI.prisonerData = currentPrisoner; // 绑定ReturnObject方法 obj.GetComponent<Button>().onClick.AddListener(() => ReturnObject(obj)); }
步骤3:修改ReturnObject方法获取数据
public void ReturnObject(GameObject obj) { PrisonerItemUI itemUI = obj.GetComponent<PrisonerItemUI>(); if (itemUI != null && itemUI.prisonerData != null) { LoadPrisonerStore(itemUI.prisonerData); } }
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

