用Unity做个游戏(六) - 原生UI组件扩展

前言

UI的框架大致搭好了,虽说还有许多控件还没支持,不过其实都大同小异,以后需要用到新的控件的时候再考虑支持新控件好了。

然而现在有个问题,UGUI原生的控件虽然已经很好用了,不过我们有时候还是会想有更多的功能,举个例子,UI.Button组件并没有保存这个按钮下的Text节点,我们不能方便地修改按钮的文本,当然这个是可以理解的,因为不是所有的按钮都需要文本,很多情况它会作为一个图片按钮出现在游戏中。

不过更多的情况按钮还是有包含一个文本的,为了方便地修改按钮的文本,我们需要对其作出一定扩展。

具体实现过程

扩展UI.Button

C#支持通过this关键字为一个类扩展方法,如下:

1
2
3
4
5
6
public static class SFUIExtension
{
static public void SetText(this Button btn, string str)
{
}
}

这样一来,UI.Button类就有了一个签名为void SetText(string)的方法了。

那么,我们就可以根据Button组件找到按钮所在的GameObject,然后在子节点中找到UI.Text控件,就可以对其进行修改了。

这样做确实work,但是不好,因为没有保存Text组件的引用,每次调用SetText()方法都必须要重新找一遍,这样做太浪费了。

那么把Text组件保存起来不就好了嘛~然而问题又来了,保存到哪儿呢,C#支持为类扩展方法,但不支持为类扩展属性。好像没地方放了orz

Button扩展

那就再弄一个新的控件来保存所有其他我们自定义的需要扩展的东西吧。于是就有了SFButtonExtension这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class SFButtonExtension : MonoBehavour
{
public Text text;
private bool m_inited = false;

void Start()
{
if (text == null)
{
text = GetComponentInChildren<Text>();
}
m_inited = true;
}

void SetText(string str)
{
text.text = str;
}

static public SFButtonExtension Get(GameObject go)
{
if (go == null)
{
return null;
}
var com = go.GetComponent<SFButtonExtension>();
if (com == null)
{
com = go.AddComponent<SFButtonExtension>();
}
if (!com.m_inited)
{
com.Start();
}
return com;
}
}

这个组件也是运行时动态添加到物体上的,原理上类似之前提到的SFUIEventListener,都是通过静态方法获取组件,获取时判断是否存在,不存在则自动创建。

补完

回到文章开始的地方,这下子就都明朗起来了:

1
2
3
4
5
6
7
8
static public void SetText(this Button btn, string str)
{
var com = SFButtonExtension.Get(btn.gameObject);
if (com != null)
{
com.SetText(str);
}
}

然后就可以在Presenter里随意地修改按钮的文本了,就像是使用Button原生的方法一样。

应用

在之前那个TestView里面的按钮逻辑里再加一句:

1
m_view.btnOk.SetText("修改了button的Text");

嗯,运行测试,一切完美:

0601

点击过按钮之后,按钮的GameObject上会自动挂载一个SFButtonExtension脚本,这个就是我们的扩展组件了

0602

完整代码

上面贴出的代码片段由于篇幅限制只保留了关键部分,完整的代码可在我的github上找到