unity中UI的触发方式
使用过unity的ugui的基本都知道通过给Button或者其他UI组件绑定需要触发的事件,然后在运行时,对对应的UI进行点击或者进行值的改变时,便会触发所绑定的事件。
触发原理以及对设计模式的思考
这种触发方式很容易让我们联想到回调函数。没错,不管是通过面板上或者代码为UI添加事件,他都是采用了回调的方式对事件进行调用。而这又让我们联想到设计模式中的一种,观察者模式。我们将对这个UI值感兴趣的方法,通过事件的方式添加到他的回调函数中,从而构成观察者(事件)与被观察者(UI)的关系。
理解回调函数 ,在我们编程时,函数或者说方法,其实就是一个代码块,我们通过函数名(代码块所在地址)来调用整个代码块。而回调函数中我们怎么才能知道什么时候需要回调呢?这就是之前讲过的对值的观察。当值发生改变的时候就会进行回调。一般可以在属性的set方法里面进行设置。例如:
// An highlighted block
public class Test
{
private int value;
public int Value
{
get { return value; }
set
{
if (value != this.value)
{
this.value = value;
//Action?.Invoke();
//执行一个委托方法,Action是委托中的一种,这句话的意思是如果委托不为空,则执行。
//我们给这个值绑定方法的话就给该Action委托添加事件
}
}
}
}
当然这只是我个人的一种理解方式
这种回调的方式在unity中有一个致命缺点
大家可能会遇到这么一个问题。
在unity中在脚本中用AddListener() 给一组UI添加触发事件
如下面代码
void Start()
{
Button[] btns = Cube.GetComponentsInChildren<Button>();
for (int i = 0; i < btns.Length; i++)
{
btns[i].onClick.AddListener(delegate
{
Onclick(i);
});
}
}
void Onclick(int i)
{
Debug.Log(i);
}
测试结果,所有的debug都输出的是for循环的最后一个i的值。
我们来分析一下为什么会出现这种情况。
我们首先获取了cube(一个UI物体名字)上所有子物体的button组件,然后通过for循环给所有的button绑定onclick事件。因为这个事件带参,所以我们通过委托的方式调用。按理来说我们点击不同的按钮输出的应该是不同的值。但是事实却并非如此!
仔细想想委托和回调的本质
回到之前的代码块执行指定的语句。没错,回到之前的代码块!也就是说我们绑定完方法之后,i值已经变成了最后一个。我们的方法传进去的值也理所当然就是最后一个!所以在unity中我们不能通过一个批处理让所有的button绑定同一个带可变参数的方法。 当然如果你有,请一定告诉我,让我学习一波,点个赞。