c# - Unity按钮单击未触发事件
问题描述
我查看了此处处理相同问题的帖子,但它既没有说明问题所在,也没有解决我的问题。
我在面板中创建了一个带有多个按钮的 Canvas 预制件。我在运行时实例化预制件并抓取Button
面板中的所有对象。然后我onClick()
为调用相同clicked()
方法的所有按钮的事件添加一个监听器
public class GameOptions
{
private GameObject canvas;
public GameOptions(GameObject canvas)
{
this.canvas = canvas;
GameObject.Instantiate(canvas);
Text[] textObjects = canvas.GetComponentsInChildren<Text>();
Button[] buttonObjects = canvas.GetComponentsInChildren<Button>();
for (int i = 0; i < buttonObjects.Length; i++)
{
Debug.Log(buttonObjects[i].name);
buttonObjects[i].onClick.AddListener(() => clicked());
buttonObjects[i].onClick.Invoke();
}
}
public void clicked()
{
Debug.Log("Clicked!");
}
}
请注意,当我通过代码调用事件时,clicked()
会调用并“单击!” 正确输出到控制台。
但是,单击时没有一个按钮会触发事件。我还注意到 Inspector 中 OnClick 中的 PersistentCalls.Calls 数组在运行时对所有按钮都有 0 个元素。
我在 Windows 10 64 中使用 Unity 2017.4.3f1。
解决方案
您没有抛出任何异常并且onClick.Invoke()
正在触发的事实表明问题在于其他一些元素正在消耗点击次数。没有你的项目在我面前,我只能提出一些建议。
- 确保相机和按钮之间没有ui元素(例如透明面板或图像);您可以在运行时移动对象以查看它们是否太靠近并消耗点击。
- 确保父画布没有
CanvasGroup
设置Interactable
为 false。 - 寻找任何可能阻碍光线投射的空物体/碰撞器/侦听器。
祝你好运!
编辑
在重新阅读您的代码并再次给链接的帖子提供一次之后,我意识到您的代码中有一个错误。
在您的GameOptions
类构造函数中,您在收集对象时实际上并没有引用实例化的对象。你写了这个:
this.canvas = canvas;
GameObject.Instantiate(canvas);
Text[] textObjects = canvas.GetComponentsInChildren<Text>();
如果您查看到底发生了什么,您正在将该字段分配给canvas
传递给构造函数参数的预制件。完成赋值后,使用参数实例化预制件,而不引用实例化对象。
之后,您将调用GetComponentsInChildren
预制而不是实例化对象本身。这就是onClick.Invoke()
被解雇的原因,因为对象存在于预制件上;他们只是不是你正在寻找的对象。
我已经重构了您的构造函数,这应该可以解决您的问题。
public GameOptions(GameObject canvas)
{
//here we instantiate the canvas item, assigning it to the field
this.canvas = GameObject.Instantiate(canvas);
//then we reference the field item, instead of the parameter item
Text[] textObjects = this.canvas.GetComponentsInChildren<Text>();
Button[] buttonObjects = this.canvas.GetComponentsInChildren<Button>();
for(int i = 0; i < buttonObjects.Length; i++)
{
Debug.Log(buttonObjects[i].name);
buttonObjects[i].onClick.AddListener(() => clicked());
buttonObjects[i].onClick.Invoke();
}
}
几点注意事项
- 即使您从未使用过该类的任何成员,您也应该使用
Canvas
item 而不是;它使以后在路上更容易阅读,并防止您意外构建当您尝试访问孩子时不会做任何事情的构造。该对象继承自,因此您将拥有所需的一切。GameObject
Canvas
new GameOptions(someRandomButton)
Canvas
GameObject
- 您应该考虑使用不同的命名方案;这是非常主观的意见,如果你搜索 SO,关于这个主题会有很多争论。就个人而言,我选择私有字段的下划线前缀,例如
private GameObject _canvas;
,这让我零怀疑我没有忘记 athis
因为参数和字段本质上将具有不同且唯一的命名方案。
接受我的建议!有很多方法可以解决问题,所以最终选择最适合您的方法。
推荐阅读
- python - SQLAlchemy 如何使用 ORM 重新创建此更新语句
- angular - Angular:为我的库使用全局样式 css:正确的方法?
- python - Snakemake - 将附加参数传递给输入函数
- python - CSH /TCSH 根据其索引遍历变量中的所有元素
- javascript - NAV-LINK - 在重定向之前测试用户输入?
- flutter - Flutter:保存大量数据的最佳方式
- javascript - Safari 从 DOM 分离元素后调用事件处理程序
- node.js - 让管理员应用程序使用某些 api 密钥为另一个应用程序中的用户预订服务
- python - Azure 函数 Blob 触发器失败 - Python
- function - 如何在 Vuejs 中创建可重用的函数?