using System.Collections.Generic; using System; using UnityEngine.EventSystems; using UnityEngine; public class ClickEvent : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler { private List listenerList = new List(); private Dictionary callBackDict = new Dictionary(); public void OnPointerDown(PointerEventData eventData) { for (int i = listenerList.Count - 1; i >= 0; i--) { listenerList[i]?.OnPointerDown(eventData); } } public void OnPointerUp(PointerEventData eventData) { for (int i = listenerList.Count - 1; i >= 0; i--) { listenerList[i]?.OnPointerUp(eventData); } } public void OnPointerClick(PointerEventData eventData) { for (int i = listenerList.Count - 1; i >= 0; i--) { listenerList[i]?.OnPointerClick(eventData); } } private void Update() { for (int i = listenerList.Count - 1; i >= 0; i--) { listenerList[i]?.Update(); } } public T Add() where T : ClickListener, new() { T t = Get(); if (t == null) { t = new T(); (t as IClickListener).OnCallBack((success) => OnReceive(success, t)); if (listenerList.Count == 0 || t is ClickButton) listenerList.Add(t); else listenerList.Insert(listenerList.Count - 1, t); } return t; } public void Remove() where T : ClickListener { if (!Contains()) return; T t = Get(); if (callBackDict.ContainsKey(t)) callBackDict.Remove(t); listenerList.Remove(t); } public void RemoveAll() { listenerList.Clear(); callBackDict.Clear(); } public T Get() where T : ClickListener { if (listenerList.Count == 0) return default; IClickListener listener = default; for (int i = listenerList.Count - 1; i >= 0; i--) { listener = listenerList[i]; if (listener is T) return (T)listener; } return default; } public bool Contains() where T : ClickListener { if (listenerList.Count == 0) return false; IClickListener listener = default; for (int i = listenerList.Count - 1; i >= 0; i--) { listener = listenerList[i]; if (listener is T) return true; } return false; } public bool ContainsCallBack() where T : ClickListener { T t = Get(); if (t == null) return false; if (callBackDict.ContainsKey(t)) { if (callBackDict[t] == null) { callBackDict.Remove(t); return false; } return true; } else return false; } public Action GetCallBack() where T : ClickListener { T t = Get(); if (t == null) return null; if (callBackDict.ContainsKey(t)) { Action callBack = callBackDict[t]; if (callBack == null) { callBackDict.Remove(t); return null; } return callBack; } else return null; } public bool HasRuning() { bool isRuning = false; foreach (var lis in listenerList) { if (lis.isRuning) { isRuning = true; break; } } return isRuning; } public T OnRegister(Action callBack) where T : ClickListener, new() { T t = Add(); if (callBackDict.ContainsKey(t)) callBackDict[t] = callBack; else callBackDict.Add(t, callBack); return t; } private Action clickCallBack = null; void OnReceive(bool success, IClickListener listener) { if (success) { if (listener is ClickButton) //单击事件 { Action cbk = GetCallBack(); if (cbk == null) return; if (HasRuning()) //有正在运行的事件检测单击事件滞后分发 { clickCallBack = cbk; } else { clickCallBack = null; ResetOther(); cbk.Invoke(); } } else //其他事件 { clickCallBack = null; ResetOther(); if (callBackDict.ContainsKey(listener)) callBackDict[listener]?.Invoke(); } } else { if (!HasRuning()) { clickCallBack?.Invoke(); clickCallBack = null; } } void ResetOther() { foreach (var btn in listenerList) { if (btn != listener) btn?.Reset(); } } } #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(ClickEvent))] class ClickEventInspector : UnityEditor.Editor { private ClickEvent clickEvent; private void OnEnable() { clickEvent = target as ClickEvent; } public override void OnInspectorGUI() { base.OnInspectorGUI(); GUILayout.Label("ClickListeners: "); IClickListener listener; for (int i = clickEvent.listenerList.Count - 1; i >= 0; i--) { listener = clickEvent.listenerList[i]; GUILayout.Label(" " + listener); } } } #endif private interface IClickListener { bool isRuning { get; set; } void OnPointerDown(PointerEventData eventData); void OnPointerUp(PointerEventData eventData); void OnPointerClick(PointerEventData eventData); void Update(); void OnCallBack(Action callBack); void Reset(); void Dispose(); } public abstract class ClickListener : IClickListener { bool IClickListener.isRuning { get => isRuning; set { isRuning = value; } } protected bool isRuning = false; protected Action callBack { get; private set; } void IClickListener.OnPointerDown(PointerEventData eventData) => OnPointerDown(eventData); void IClickListener.OnPointerUp(PointerEventData eventData) => OnPointerUp(eventData); void IClickListener.OnPointerClick(PointerEventData eventData) => OnPointerClick(eventData); void IClickListener.Update() => Update(); void IClickListener.Reset() => Reset(); void IClickListener.Dispose() => Dispose(); void IClickListener.OnCallBack(Action callBack) { this.callBack = callBack; } protected virtual void OnPointerDown(PointerEventData eventData) { } protected virtual void OnPointerUp(PointerEventData eventData) { } protected virtual void OnPointerClick(PointerEventData eventData) { } protected virtual void Update() { } protected abstract void Reset(); protected virtual void Dispose() { callBack = null; } } }