對於Unity回撥、監聽與廣播的使用總結

Hana的小跟班發表於2020-12-24

1.回撥方法

瞭解這個得先去了解委託。

1.UIItem類 這個類用來被例項化

回撥就是在例項化一個物件的同時,將某個方法註冊到裡面。
例如:
1:UIItem這個類中,宣告瞭一個以UIItem為引數、返回值為void的委託型別變數ItemAction。
2:在IninItem方法中,給一些屬性賦值,給ItemAction賦值(這個值必須引數是UIItem型別,且沒有返回值)。
3:新增相應事件。這裡通過一個方法ItemClick()去執行ItemAction這個委託所存的方法。
	
using System.Net.Mime;
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
public class UIItem : MonoBehaviour 
{
    public Text Item;
    //宣告一個委託型別變數
    private Action<UIItem> ItemAction;
    public string type;
    private string Type{
        get{return this.type;}
        set{this.type = value;}
    }

    public string itemName;
    private string ItemName{
        get{return this.name;}
        set{this.itemName = value;}
    }
    public Vector3 pos;
    private Vector3 Pos{
        get{return this.pos;}
        set{this.pos = value;}
    }
    /// <summary>
    /// Item初始化函式
    /// </summary>
    /// <param name="name">控制指令碼傳進來的Name</param>
    /// <param name="action">回撥函式</param>
    public void InitItem(string name, string _type, Action<UIItem> action)
    {
        Item.text = name;
        this.itemName = name;
        this.type = _type;
        ItemAction = action;
    }

    public void InitItem(string name, string _type, Vector3 _go, Action<UIItem> action)
    {
        Item.text = name;
        this.itemName = name;
        this.type = _type;

        this.pos = _go;
        ItemAction = action;
    }

    /// <summary>
    /// Item點選函式
    /// </summary>
    public void ItemClick()
    {
        //Debug.Log("點選我了");
        if (ItemAction != null)
        {
            Hashtable args = new Hashtable();
            args.Add("按鈕名稱", this.ItemName.ToString());
            args.Add("按鈕型別", this.Type.ToString() );
            args.Add("按鈕位置", this.Pos);
            BaseHEvent hEvent = new BaseHEvent(BaseHEventType.GAME_WIN, args, this);
            //傳送事件碼
            HEventDispatcher.instance().DispatchEvent(hEvent);
            //這裡就是執行委託ItemAction中儲存的方法。
            ItemAction(this);
        }
    }
}

2.UIScroller類 這個類用來例項化物件,並新增回撥方法

在這個類中,可以通過很多種方式去呼叫UIitem類中的InitItem方法去例項化UIItem物件,並傳入一個回撥方法
這時,當UIItem中的 ItemClick方法觸發時,就會回撥UIScroller中的ShowItemInfo這個回撥方法(注意,這個方法的引數必須是UIItem)。

using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIScroller: MonoBehaviour
{
    public GameObject ItemObject;
    public Transform ItemGrid;
    private List<GameObject> ItemCacheds = new List<GameObject>();
    private List<string> ItemNameList = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8","9" };
    void Start()
    {
        for (int i = 0; i < ItemNameList.Count; i++)
        {       
            GameObject tempObject = Instantiate(ItemObject);
            tempObject.transform.parent = ItemGrid.transform;
            tempObject.transform.localScale = ItemObject.transform.localScale;
            Debug.Log(tempObject.transform.localPosition);
            Debug.Log(tempObject.GetComponent<RectTransform>().localPosition);
            tempObject.transform.name = ItemNameList[i];
           //例項一個UIItem物件,並新增一個回撥方法
            tempObject.GetComponent<UIItem>().InitItem(ItemNameList[i], "按鈕", tempObject.GetComponent<RectTransform>().localPosition ,ShowItemInfo);
            ItemCacheds.Add(tempObject);
        }
        for (int i = 0; i < ItemCacheds.Count; i++)
        {
            Debug.Log(ItemCacheds[i].GetComponent<RectTransform>().position);
        }
    }
    /// <summary>
    /// 回撥函式
    /// </summary>
    /// <param name="item">呼叫的Item物件</param>
    private void ShowItemInfo(UIItem item)
    { 
        if (item != null)
        {
            Debug.LogError("----->This Item Name is " + item.Item.text);
        }        
    }
}

總結一下回撥方法:就是在例項化的同時繫結了一個方法, 以按鈕為例,按鈕僅僅監聽點選事件,而點選之後的一些事情與它無關。 當觸發回撥的時候,就可以獲取到當前的這個按鈕(UIitem)的一些資訊或者是處理過某些資料之後的得到資料,回撥就可以用這些資料做一些其他的事情。實際上Unity中的button就是這麼實現的

2.事件監聽與廣播

事件碼:

事件碼可以看作成一個key,事件看成一個value。
一個事件碼可以繫結多個事件(委託的特性)

監聽:

就是把事件繫結到事件碼上

廣播:

就是把某個事件碼儲存的事件全部執行。

事件基類

在上面UIItem的ItemClick方法中,有HEventDispatcher.instance().DispatchEvent(hEvent);呼叫了這個方法,這裡就是去廣播hEvent這裡面存的事件碼。

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

//定義委託用於傳事件基類
public delegate void HEventListenerDelegate(BaseHEvent hEvent);
/// <summary>
/// 事件機制類 用於監聽  移除事件
/// </summary>
public class HEventDispatcher
{
    static HEventDispatcher Instance;
    //單例
    public static HEventDispatcher instance()
    {
        if(Instance == null)
        {
            Instance = new HEventDispatcher();
        } 
        return Instance;
    }

    //掌控所有型別得委託事件
    private Hashtable listeners = new Hashtable();

    /// <summary>
    /// 新增監聽
    /// </summary>
    /// <param name="事件型別"></param>
    /// <param name="事件基類"></param>
    public void AddEventListener(BaseHEventType _type, HEventListenerDelegate _listener)
    {
        //先獲取之間這個型別的委託 如果沒有就為null
        HEventListenerDelegate hEventListenerDelegate = this.listeners[_type] as HEventListenerDelegate;
        //將傳入的委託呼叫列表 連線到一起
        hEventListenerDelegate = (HEventListenerDelegate) Delegate.Combine(hEventListenerDelegate, _listener);
        //重新給hashtable表中的事件型別賦值
        this.listeners[_type] = hEventListenerDelegate;
    }

    //移除監聽
    public void RemoveEventListener(BaseHEventType _type, HEventListenerDelegate _listener)
    {
        //先獲取之間這個型別的委託 如果沒有就為null
        HEventListenerDelegate hEventListenerDelegate = this.listeners[_type] as HEventListenerDelegate;
        if(hEventListenerDelegate != null)
        {
            //將傳入的委託呼叫列表 移除
            hEventListenerDelegate = (HEventListenerDelegate) Delegate.Remove(hEventListenerDelegate, _listener);
            //重新給hashtable表中的事件型別賦值
            this.listeners[_type] = hEventListenerDelegate;
        }
    }

    //排程
    public void  DispatchEvent(BaseHEvent _baseH)
    {
        HEventListenerDelegate hEventListenerDelegate = this.listeners[_baseH.Type] as HEventListenerDelegate;
        if(hEventListenerDelegate != null)
        {
            try{
                hEventListenerDelegate(_baseH);//執行委託
            }catch(Exception e)
            {
                throw new System.Exception(string.Concat(new string[] { "Error Dispatch event", 
                _baseH.Type.ToString(), ":", e.Message, " ", e.StackTrace }), e);
            }
        }
    }
    
    //清空
    public void RemoveAll()
    {
        this.listeners.Clear();
    }
}

在具體的某個類中去新增監聽,繫結一個事件碼和一個事件即可。
新增監聽 AddEventListener(BaseHEventType.GAME_WIN, HidenCube);就是一個事件碼和一個方法

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cube : MonoBehaviour
{  
    private void OnEnable() 
    {
//新增監聽        
		HEventDispatcher.instance().AddEventListener(BaseHEventType.GAME_WIN, HidenCube);
    }
    private void OnDestroy() {
        HEventDispatcher.instance().RemoveEventListener(BaseHEventType.GAME_WIN, HidenCube);
    }
    //新增事件方法
    void HidenCube(BaseHEvent hEvent)
    {
        ///this.gameObject.SetActive(!this.gameObject.activeInHierarchy);
        //Debug.Log("事件碼:" + hEvent.Type);
        if(hEvent.Params!=null)
        {            
            foreach (DictionaryEntry item in hEvent.Params)
            {
                Debug.Log(item.Key + "  " + item.Value);
            }
        }
    }
}

連結:[https://pan.baidu.com/s/1tz9KmTMMsYMWvwnHCHfXCw](https://pan.baidu.com/s/1tz9KmTMMsYMWvwnHCHfXCw) 
提取碼:vmc3 
複製這段內容後開啟百度網盤手機App,操作更方便哦

參考連結:
[https://blog.csdn.net/hnzmdlhc/article/details/89033423](https://blog.csdn.net/hnzmdlhc/article/details/89033423)
[https://www.cnblogs.com/mrmocha/p/8016599.html](https://www.cnblogs.com/mrmocha/p/8016599.html)

相關文章