Unity仿照Android ButterKnife

為了減少GetComponent的使用 依照ButterKnife的Unity ButterKnife

using System;
using System.Reflection;
using UnityEngine;
using System.Collections.Generic;

public class Knife : Singleton<Knife>
{
	public void Bind (Component compon)
	{	
		FieldInfo[] fields = compon.GetType ().GetFields ();

		setInfoValue (fields, compon.gameObject, compon);
	}

	public T Bind<T> (GameObject go) where T : new()
	{
		T classType = new T ();

		FieldInfo[] fields = typeof(T).GetFields ();

		setInfoValue (fields, go, classType);

		return classType;
	}

	void setInfoValue (FieldInfo[] fields, GameObject go, System.Object classType)
	{
		for (int j = 0; j < fields.Length; j++) {
			
			FieldInfo info = fields [j];
		
			var view = Attribute.GetCustomAttribute (info, typeof(DIAttribute));

			if (view == null) {
				continue;
			}

			Type type = info.FieldType;

			if (view is BindView) {

				BindView bindView = view as BindView;

				if (type.IsArray) {

					if (bindView.typeObj == null) {
						Debug.LogErrorFormat ("{0}is get array , but typeof() is null, please check ", bindView.goPath);
						return;
					}

					var parent = go.transform.Find (bindView.goPath);

					Array filledArray = Array.CreateInstance (bindView.typeObj, parent.childCount);

					for (int i = 0; i < parent.childCount; i++) {

						var child = parent.transform.GetChild (i);

						if (bindView.typeObj == typeof(GameObject)) {
							filledArray.SetValue (child.gameObject, i);
						} else {
							filledArray.SetValue (child.gameObject.transform.GetOrAddComponent (bindView.typeObj), i);
						}
					}

					info.SetValue (classType, filledArray);

				} else {

					var findChildGo = go.transform.FindChild (bindView.goPath);

					if (findChildGo != null) {

						if (type.Equals (typeof(GameObject))) {
							info.SetValue (classType, findChildGo.gameObject);
						} else {
							info.SetValue (classType, findChildGo.gameObject.transform.GetOrAddComponent (type));
						}

					} else
						Debug.LogErrorFormat ("[Parent]{0}.transform.FindChild(Path:{1}) is null,check GameObejct it exist and path is right.", go.name, bindView.goPath);

				}
			}
		}
	}
     
}
using UnityEngine;
using System;

public class BindView : DIAttribute
{
	public readonly string goPath;

	public readonly Type typeObj;

	public BindView (string goPath, Type typeObj = null)
	{
		this.goPath = goPath;

		this.typeObj = typeObj;
	}

}

BindView繼承DIAttribute 代入指定GameOjbect的路徑

Knife在Bind的時候會知道要從哪個Comonent或GameObject身上取得FieldInfo[]的資訊

利用Attribute.GetCustomAttribute獲取要從哪個GameObject身上獲得哪個Component

如果指定的GameObject身上沒有該Component 就會新增並取得(GetOrAddComponent)

使用範例

單個Component取得

[BindView("scaler/Scroll View/Viewport/Content/round_set/set_toggle")]
public Toggle RoundSetToggle;

從scaler/Scroll View/Viewport/Content/round_set/set_toggle的GameObject上需要取得Toggle的Component

需設為Publich才找得到

取得的Component為Array

[BindView("scaler/sound", typeof(AudioSource))]
public AudioSource[] sound;

在scaler/sound下的所有child GetorAddComponent<AudioSource>();

Bind<T>使用

Holder holder = Knife.Instance.Bind<Holder> (gameObject);

在gameobject底下尋找Holder類別BindView