Unity开发过程中,控件的获取是件繁琐的工作。Android的ButterKnife可很好绑定控件,以此为灵感,在Unity中实现了控件的注解绑定。
步骤一:自定义属性
[AttributeUsage(AttributeTargets.Field)]
public class ComponentKey : Attribute
{
private string key;
public string Key => key;
public ComponentKey(string key)
{
this.key = key;
}
}
[AttributeUsage(AttributeTargets.Field)]为字段属性。key为对应的控件关键字。
步骤二:定义基类ButterKnifeBaseView
public class ButterKnifeBaseView : MonoBehaviour
{
private static readonly List<string> keyHeads = new List<string>()
{
"btn_", "image_", "txt_", "ipt_"
};
private Dictionary<string, GameObject> _dicObjectList = new Dictionary<string, GameObject>();
protected virtual void Awake()
{
InitComponent();
ButterKnifeBind();
}
private void ButterKnifeBind()
{
var type = GetType();
var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var fieldInfo in fieldInfos)
{
var attribute = fieldInfo.GetCustomAttributes(typeof(ComponentKey)).FirstOrDefault();
if (attribute != null && attribute is ComponentKey)
{
var componentKey = (attribute as ComponentKey).Key;
var component = GetComponentByObjName(fieldInfo.FieldType, componentKey);
fieldInfo.SetValue(this, component);
}
}
}
private void InitComponent()
{
var childArray = GetComponentsInChildren<Transform>(true);
if (childArray != null && childArray.Length > 0)
{
foreach (var childTf in childArray)
{
int index = childTf.name.IndexOf("_", StringComparison.Ordinal);
if (index == -1)
{
continue;
}
string head = childTf.name.Substring(0, index + 1);
if (keyHeads.Contains(head))
{
if (!_dicObjectList.ContainsKey(childTf.name))
{
_dicObjectList[childTf.name] = childTf.gameObject;
}
else
{
Debug.LogError(string.Format("key:{0} has exist,please check", childTf.name));
}
}
}
}
}
protected Component GetComponentByObjName(Type type, string name)
{
if (_dicObjectList.ContainsKey(name) && _dicObjectList[name] != null)
{
return _dicObjectList[name].GetComponent(type);
}
return null;
}
}
关键方法ButterKnifeBind通过反射获取控件中属性值。获取控件通过Type方法获取。获取完后, fieldInfo.SetValue(this, component)将值设置到控件中即可
步骤三:预制中需绑定的脚本
[AASKey("TestButterKnifePrefab")]
public class TestButterKnifePrefab : ButterKnifeBaseView
{
[ComponentKey("btn_click")] private Button btn_click;
[ComponentKey("txt_content")] private Text txt_content;
[ComponentKey("image_bg")] private Image image_bg;
[ComponentKey("ipt_name")] private InputField ipt_name;
private const string Sprite_Key = "TestImage";
private void Awake()
{
base.Awake();
btn_click.onClick.AddListener(OnBtnClick);
txt_content.text = "hello world!!!";
ipt_name.text = "unity3d";
Addressables.LoadAssetAsync<Sprite>(Sprite_Key).Completed += op => { image_bg.sprite = op.Result; };
}
private void OnBtnClick()
{
Debug.LogError("OnBtnClick Event");
}
}
使用方式简单,只要在控件变量中定义属性的key即可获取到控件。可以很方便程序开发。
利用反射的方式获取控件缺点:反射比较耗性能,故需实例化大量的预制不推荐使用此方式。
步骤四:资源获取
https://download.youkuaiyun.com/download/EIE08027/11970159
免费获取,可以加我qq:416390409获取,备注csdn
TODO 后期会更新用编辑器的方式动态生成控件定义的基础脚本,使用只要实现逻辑部分。这样会更方便大家的使用。