/******************************************************************** 文件: ButtonEx.cs 作者: 梦语 邮箱: 1982614048@qq.com 创建时间: 2024/03/29 17:28:19 最后修改: 梦语 最后修改时间: 2024/04/22 20:20:24 功能: 高级按钮扩展 *********************************************************************/ using Sirenix.OdinInspector; using System; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; using UnityTimer; namespace Ether { public class ButtonExPointerData : Selectable { public GameObject PointerItem; //点击的Item public Vector3 lastPosition; //上次的位置 /// /// 是否在拖拽 /// public bool IsDrag { get { Vector3 curPos = PointerItem.transform.position; Vector3 offset = curPos - lastPosition; if (Mathf.Abs(offset.x) <= 10 && Mathf.Abs(offset.y) <= 10 && Mathf.Abs(offset.z) <= 10) { return false; } return true; } } } [Serializable] public class ButtonEx : SerializedMonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler { #region 面板数据 [Header("音效")] [Space] [LabelText("点击音效")] [ValueDropdown("@ConstName.AudioNameList")] public string clickSound; [LabelText("移入音效")] [ValueDropdown("@ConstName.AudioNameList")] public string enterSound; [Space] [Space] [LabelText("是否点击缩放")] public bool isScale = true; [LabelText("点击缩放大小"), Range(0, 2)] [ShowIf("isScale", true)] public float clickScale = 0.95f; [Space] [LabelText("是否允许长按")] public bool allowLongPress = true; [ShowIf("allowLongPress", true), LabelText("触发长按时间")] public float longPressDuration = 1f; [ShowIf("allowLongPress", true), LabelText("是否允许长按循环触发")] public bool allowLongPressWhile = true; [Space] [LabelText("是否允许双击")] public bool allowDoubleClick = false; [ShowIf("allowDoubleClick", true), Tooltip("第二次点击与第一次点击的间隔"), LabelText("点击间隔"), Range(0.2f, 1.5f)] public float doubleClickDuration = 0.5f; [Space] [SerializeField, LabelText("使用不规则点击"), SetProperty("UseAnomalousClick")] private bool useAnomalousClick = false; public bool UseAnomalousClick { get { return useAnomalousClick; } set { useAnomalousClick = value; Debug.Log("UseAnomalousClick"); } } [LabelText("是否打印Log")] public bool isShowLog = false; #endregion #region 事件 /// /// 按钮点击事件 /// private ActionEvent m_OnClick = new ActionEvent(); public ActionEvent OnClick { get { return m_OnClick; } } /// /// 按钮左键点击事件 /// private ActionEvent m_OnLeftClick = new ActionEvent(); public ActionEvent OnLeftClick { get { return m_OnLeftClick; } } /// /// 按钮右键点击事件 /// private ActionEvent m_OnRightClick = new ActionEvent(); public ActionEvent OnRightClick { get { return m_OnRightClick; } } /// /// 按钮点击事件 /// private ActionEvent m_OnDoubleClick = new ActionEvent(); public ActionEvent OnDoubleClick { get { return m_OnDoubleClick; } } /// /// 按钮长按点击事件 /// private ActionEvent m_OnLongClick = new ActionEvent(); public ActionEvent OnLongClick { get { return m_OnLongClick; } } /// /// 按钮进入事件 /// private ActionEvent m_OnEnter = new ActionEvent(); public ActionEvent OnEnter { get { return m_OnEnter; } } /// /// 按钮移出事件 /// private ActionEvent m_OnExit = new ActionEvent(); public ActionEvent OnExit { get { return m_OnExit; } } public void Awake() { BaseScale = transform.localScale; pointerData = new ButtonExPointerData() { PointerItem = gameObject, }; } ButtonExPointerData pointerData; //按钮数据 public Vector3 BaseScale { get; private set; } private Vector3 normalScale = Vector3.zero; //基础缩放 private bool isOnClickDown = false; //是否点击按下 private bool isOnClickTrigger = false; //是否触发点击 private bool isDoubleClicking = false; //是否正在双击状态 private bool isLongPressing = false; //是否长按状态 private Timer longPressTimer; //长按定时器 private Timer doubleTimer; //双击定时器 #region 按下 public void OnPointerDown(PointerEventData eventData) { normalScale = transform.localScale; //if (eventData.button != PointerEventData.InputButton.Left) // return; pointerData.lastPosition = transform.position; OnPointerDownEvent(); } private void OnPointerDownEvent() { if (isShowLog) { Debug.Log("按钮按下"); } isOnClickDown = true; isOnClickTrigger = true; isLongPressing = false; if (isScale) { transform.localScale = new Vector2(normalScale.x * clickScale, normalScale.y * clickScale); } StartLongPress(); } #endregion #region 抬起 public void OnPointerUp(PointerEventData eventData) { if (!isActiveAndEnabled) return; //if (eventData.button != PointerEventData.InputButton.Left) // return; if (isOnClickTrigger && !isLongPressing) { if (isDoubleClicking) { return; } if (allowDoubleClick) { isDoubleClicking = true; doubleTimer = Timer.Register(doubleClickDuration, () => { isDoubleClicking = false; if (isOnClickTrigger) { OnPointerDoubleClick(eventData); OnPointerUpEvent(eventData); //因为上面return掉了,所以第二次的up没有执行,得手动调用 } else { OnPointerClick(eventData); } }); } else { OnPointerClick(eventData); } } OnPointerUpEvent(eventData); } private void OnPointerUpEvent(PointerEventData eventData) { isOnClickDown = false; isOnClickTrigger = false; isLongPressing = false; if (isScale) { transform.localScale = normalScale; } StopLongPress(); if (eventData.dragging) { return; } if (isShowLog) { Debug.Log("按钮抬起"); } } #endregion #region 点击 public void OnPointerClick(PointerEventData eventData) { if (eventData.dragging) { return; } if (isShowLog) { Debug.Log($"{transform.name}按钮点击"); } if (m_OnClick.Count == 0) { if (eventData.button == PointerEventData.InputButton.Left) { m_OnLeftClick.Invoke(); } else if (eventData.button == PointerEventData.InputButton.Right) { m_OnRightClick.Invoke(); } } else { m_OnClick.Invoke(); } if (!string.IsNullOrEmpty(clickSound)) { AudioManager.Inst.PlayEffectAudio(clickSound); } } public void OnPointerDoubleClick(PointerEventData eventData) { if (eventData.dragging) { return; } if (isShowLog) { Debug.Log($"{transform.name}按钮双击"); } m_OnDoubleClick.Invoke(); if (!string.IsNullOrEmpty(clickSound)) { AudioManager.Inst.PlayEffectAudio(clickSound); } } #endregion #region 移入 public void OnPointerEnter(PointerEventData eventData) { //Debug.Log("移入按钮"); m_OnEnter?.Invoke(); if (!string.IsNullOrEmpty(enterSound)) { AudioManager.Inst.PlayEffectAudio(enterSound); } if (isOnClickDown) { isOnClickTrigger = true; if (isScale) { transform.localScale = new Vector2(normalScale.x * clickScale, normalScale.y * clickScale); } StartLongPress(); } } #endregion #region 移出 public void OnPointerExit(PointerEventData eventData) { isOnClickTrigger = false; isLongPressing = false; // if (isOnClickDown && isScale) // { // transform.localScale = normalScale; // } StopLongPress(); m_OnExit?.Invoke(); } #endregion #region 长按 /// /// 开始长按 /// private void StartLongPress() { if (allowLongPress) { longPressTimer = Timer.Register(longPressDuration, () => { if (pointerData.IsDrag) { isOnClickDown = false; isOnClickTrigger = false; isLongPressing = false; StopLongPress(); return; } isLongPressing = true; OnPointerLongClick(); }, isLooped: allowLongPressWhile); } } /// /// 长按触发 /// private void OnPointerLongClick() { if (isShowLog) { Debug.Log("按钮长按!"); } m_OnLongClick.Invoke(); } /// /// 停止长按 /// private void StopLongPress() { longPressTimer?.Cancel(); } #endregion #endregion #if UNITY_EDITOR [MenuItem("GameObject/UIEx/ButtonEx", priority = -998)] private static void CreateButtonEx(MenuCommand menuCmd) { GameObject selection = Selection.activeGameObject; CommonExtension.CreateComponent(selection, (obj) => { }, typeof(Image)); } #endif } }