Unity中如何自动缓存所需的UI组件

本文介绍了一种游戏开发中UI组件自动引用的方法,通过反射和递归查找,避免了因UI层级变化导致的代码修改,实现了组件引用的动态绑定,极大地提高了开发效率。

在游戏开发中,拼UI界面和写UI逻辑是少不了,甚至是绝大多数的事。

写UI逻辑时候,我们如果经常要引用到一个Image组件,名字例如为img1,首次接触游戏开发得你可能会这样写,声明一个变量,通过调用transform.Find("节点路径1/img1").GetComponent<Image>()来缓存组件引用。如果有其他组件ScrollRect scrollRect2,GameObject panel3也同上操作。

public class BaseView : MonoBehaviour
{
    Image img1;
    ScrollRect scrollRect2;
    ...
	GameObject panel3;
	
    private void Awake()
    {
        img1= transform.Find("节点路径1/img1").GetComponent<Image>();
        scrollRect2 = transform.Find("节点路径2/scrollRect2").GetComponent<ScrollRect>();
        ...
        panel3 = transform.Find("节点路径3/panel3").gameObject;
    }
}

但是这样写的话有个弊端,如果后期优化的时候,拼UI的同学变动了节点层级路径,那么代码里的节点路径也得相应的变动,并且节点路径本身也极其容易写错。

于是,你可能会想到通过递归查找节点名字来获取节点。这样,只要节点名字不变,节点层级的变动在代码层是无感的。

    private void Awake()
    {
        img1 = FindDeep(transform, "img1").GetComponent<Image>();
        scrollRect2 = FindDeep(transform, "scrollRect2").GetComponent<ScrollRect>();
        ...
        panel3 = FindDeep(transform, "panel3").gameObject;
    }

    Transform FindDeep(Transform t, string childName)
    {
        if (t.name.Equals(childName))
            return t;
        for (int i = 0; i < t.childCount; ++i)
        {
            var child = FindDeep(t.GetChild(i), childName);
            if (child) return child;
        }

        return null;
    }

到这里,其实已经能应付绝大多数情况了。

但是作者君懒啊,实现不想每引用一个组件都写一遍缓存组件的代码。在作者君看来程序员就是要来消灭重复的。于是在掉了几根头发以后,作者君想到利用反射获取需要缓存的引用和其组件类型,接着同样利用反射设置该引用的值

public class BaseView : MonoBehaviour
{
    public Image img1;
    public ScrollRect scrollRect2;
    ...
	public GameObject panel3;

    private void Awake()
    {
        var fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); // 获取public变量
        foreach (var field in fields)
        {
            var name = field.Name;
            Transform obj = Utils.FindDeep(transform, name); // 递归查找节点

            if (obj != null)
            {
                if (typeof(GameObject).Equals(field.FieldType))
                {
                    field.SetValue(this, obj.gameObject);
                }
                else
                {
                    field.SetValue(this, obj.GetComponent(field.FieldType)); // 获取组件类型,有时候你会觉得Unity很贴心
                }
            }
        }
    }
}

从而在继承了BaseView的界面脚本里,所有public组件成员引用都可以被脚本自动缓存。只需18行代码,永久省去所有缓存组件的代码,一次编写,终生享受!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值