UGUI 源码研究及扩展 :EventTrigger

在处理Unity UI的各种响应事件的时候,一个Button往往会不太够用,UGUI提供了对所有响应事件封装的一个类EventTrigger,但尽量不要使用它,一是它的调用方式不是很友好,这种情况后文会给出一些扩展方法使得它可以简单运用。第二个原因也是主要原是由于他的方法调用会影响性能,这一点也会在后文进行解释。文章最后的扩展类也对所有的接口函数的触发时机和顺序做了注释。先来看一下这个类源码的核心。

1.Triggers

首先这个类定义了一个触发器列表,我们可以通过triggers.add(...)来添加触发器,但是这中添加方式不太友好,需要对Entry进行类型以及回调函数的设置,用起来比较麻烦,后面会有一系列对EventTrigger的扩展方法,简化了这一流程。

private List<Entry> m_Delegates;

public List<Entry> triggers
{
    get
    {
        if (m_Delegates == null)
            m_Delegates = new List<Entry>();
        return m_Delegates;
    }
    set { m_Delegates = value; }
}
public class Entry
{
    public EventTriggerType eventID = EventTriggerType.PointerClick;
    public TriggerEvent callback = new TriggerEvent();
}

2.Excute()

EventTrigger类实现了所有Handler接口函数,并在这些函数中调用了Excute方法。从代码中我们可以看出Excute遍历了triggers列表并比较了EventTriggerType,如果相等并且委托不为空,则执行注册过的回调函数。触发器数量越多,for循环的次数就会越多,会造成性能上的损耗。

private void Execute(EventTriggerType id, BaseEventData eventData)
{
    for (int i = 0, imax = triggers.Count; i < imax; ++i)
    {
        var ent = triggers[i];
        if (ent.eventID == id && ent.callback != null)
            ent.callback.Invoke(eventData);
    }
}

public virtual void OnPointerEnter(PointerEventData eventData)
{
    Execute(EventTriggerType.PointerEnter, eventData);
}

public virtual void OnPointerExit(PointerEventData eventData)
{
    Execute(EventTriggerType.PointerExit, eventData);
}

public virtual void OnDrag(PointerEventData eventData)
{
    Execute(EventTriggerType.Drag, eventData);
}

public virtual void OnDrop(PointerEventData eventData)
{
    Execute(EventTriggerType.Drop, eventData);
}

public virtual void OnPointerDown(PointerEventData eventData)
{
    Execute(EventTriggerType.PointerDown, eventData);
}

public virtual void OnPointerUp(PointerEventData eventData)
{
    Execute(EventTriggerType.PointerUp, eventData);
}

public virtual void OnPointerClick(PointerEventData eventData)
{
    Execute(EventTriggerType.PointerClick, eventData);
}

public virtual void OnSelect(BaseEventData eventData)
{
    Execute(EventTriggerType.Select, eventData);
}

public virtual void OnDeselect(BaseEventData eventData)
{
    Execute(EventTriggerType.Deselect, eventData);
}

public virtual void OnScroll(PointerEventData eventData)
{
    Execute(EventTriggerType.Scroll, eventData);
}

public virtual void OnMove(AxisEventData eventData)
{
    Execute(EventTriggerType.Move, eventData);
}

public virtual void OnUpdateSelected(BaseEventData eventData)
{
    Execute(EventTriggerType.UpdateSelected, eventData);
}

public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
    Execute(EventTriggerType.InitializePotentialDrag, eventData);
}

public virtual void OnBeginDrag(PointerEventData eventData)
{
    Execute(EventTriggerType.BeginDrag, eventData);
}

public virtual void OnEndDrag(PointerEventData eventData)
{
    Execute(EventTriggerType.EndDrag, eventData);
}

public virtual void OnSubmit(BaseEventData eventData)
{
    Execute(EventTriggerType.Submit, eventData);
}

public virtual void OnCancel(BaseEventData eventData)
{
    Execute(EventTriggerType.Cancel, eventData);
}

3.扩展

对EventTrigger的使用可以分为两种,一是直接在界面添加对应类型的触发器,然后拖拽方法,这个和Button是一样的。第二种方法是动态添加,它的大致流程如下:

private EventTrigger eventTrigger;

private void Start()
{
    eventTrigger = GetComponent<EventTrigger>();
    EventTrigger.Entry entry = new EventTrigger.Entry();   // 新建触发器
    entry.eventID = EventTriggerType.PointerClick;         // 设置我们想要的触发器类型,具体可以看官方API
    entry.callback.AddListener(CallBack);                  // 给触发器添加回调函数
    eventTrigger.triggers.Add(entry);                      // 添加触发器

}
private void CallBack(BaseEventData data)
{
    // 方法类容
}

接下来是对EventTrigger的扩展,通过拓展函数,直接对eventTrigger调用对应的add方法就可以了

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

/// <summary>
/// 对Unity UI的扩展方法
/// </summary>
public static class UIExtFun
{

    /// <summary>
    /// 鼠标进入
    /// </summary>
    public static void AddOnPointerEnter(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.PointerEnter);
    }

    /// <summary>
    /// 鼠标移出
    /// </summary>
    public static void AddOnPointerExit(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.PointerExit);
    }

    /// <summary>
    /// 鼠标按下
    /// </summary>
    public static void AddOnPointerDown(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.PointerDown);
    }

    /// <summary>
    /// 鼠标抬起
    /// </summary>
    public static void AddOnPointerUp(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.PointerUp);
    }

    /// <summary>
    /// 鼠标点击(鼠标抬起时已不在原UI上时不会触发,在PointerUp之后调用)
    /// </summary>
    public static void AddOnPointerClick(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.PointerClick);
    }

    /// <summary>
    /// 鼠标拖拽时(鼠标按下不移动不会触发)
    /// </summary>
    public static void AddOnDrag(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Drag);
    }

    /// <summary>
    /// 拖拽结束时鼠标不在被拖拽UI上并且在宁外一个UI上时触发(在PointerUp之后)
    /// </summary>
    public static void AddOnDrop(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Drop);
    }

    /// <summary>
    /// 滑轮滚动时
    /// </summary>
    public static void AddOnScroll(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Scroll);
    }

    #region 物体被选中时并满足相应条件触发(用EventSystem.current.SetSelectedGameObject(gameObject)选中物体)

    /// <summary>
    /// 在被选中时
    /// </summary>
    public static void AddOnSelect(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Select);
    }

    /// <summary>
    /// 被选中后的每一帧
    /// </summary>
    public static void AddOnUpdateSelect(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.UpdateSelected);
    }

    /// <summary>
    /// 结束选中时
    /// </summary>
    public static void AddOnDeselect(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Deselect);
    }

    /// <summary>
    /// 按方向键时
    /// </summary>
    public static void AddOnMove(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Move);
    }
    public static void AddOnMove(this EventTrigger eventTrigger, UnityAction<BaseEventData> call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Move);
    }

    /// <summary>
    /// 默认为Enter键
    /// </summary>
    public static void AddOnSubmit(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Submit);
    }

    /// <summary>
    /// 默认为Esc键
    /// </summary>
    public static void AddOnCancel(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.Cancel);
    }

    #endregion

    /// <summary>
    /// 初始化拖拽(在PointerDown之后,PoinerUp之前调用,点击就会调用)
    /// </summary>
    public static void AddOnInitializePotentialDrag(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.InitializePotentialDrag);
    }

    /// <summary>
    /// 拖拽开始(鼠标按下不移动不会触发)
    /// </summary>
    public static void AddOnBeginDrag(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.BeginDrag);
    }

    /// <summary>
    /// 拖拽结束(鼠标按下不移动不会触发,在Drop之后)
    /// </summary>
    public static void AddOnEndDrag(this EventTrigger eventTrigger, UnityAction call)
    {
        AddCall(eventTrigger, call, EventTriggerType.EndDrag);
    }

    /// <summary>
    /// 给EventTrigger添加Entry
    /// </summary>
    private static void AddCall(EventTrigger eventTrigger, UnityAction call, EventTriggerType type)
    {
        EventTrigger.Entry myclick = new EventTrigger.Entry
        {
            eventID = type,
        };

        // ?.操作符是c#6.0提供的新特性,需要将工程升级到.net4.x,具体可以自己查阅相关信息
        myclick.callback.AddListener((BaseEventData data) => { call?.Invoke(); });
        eventTrigger.triggers.Add(myclick);
    }

    /// <summary>
    /// 提供一种开放BaseEventData的重载
    /// 需要BaseEventData的事件也要写重载,上面我只对AddOnMove做了重载
    /// </summary>
    private static void AddCall(EventTrigger eventTrigger, UnityAction<BaseEventData> call, EventTriggerType type)
    {
        EventTrigger.Entry myclick = new EventTrigger.Entry
        {
            eventID = type,
        };
        myclick.callback.AddListener((BaseEventData data) => { call?.Invoke(data); });
        eventTrigger.triggers.Add(myclick);
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
EventTrigger是Unity中的一个组件,用于处理游戏对象上的事件触发。它继承了许多事件接口,为开发者提供了方便的事件处理功能。通过使用EventTrigger,开发者可以在特定的事件发生时执行自定义的操作。 在Unity中,EventTrigger可以用于许多场景,比如在用户点击按钮时触发某个动作,或者在鼠标进入某个区域时触发某个效果等。它可以与其他Unity插件或扩展一起使用,例如Ultimate FPS (UFPS)、Uni2D和Vectrosity等。 在EventTrigger中,有多个事件可以进行配置,例如PointerClick事件、PointerEnter事件和PointerExit事件等。每个事件可以与一个或多个自定义方法关联,以在事件发生时执行相应的操作。 举个例子,当用户点击一个按钮时,可以通过配置EventTrigger的PointerClick事件来调用一个自定义的方法,来处理按钮点击事件。同样地,当鼠标进入或退出某个区域时,可以通过配置EventTrigger的PointerEnter和PointerExit事件来执行相应的操作。 总之,Unity的EventTrigger提供了一个灵活的事件触发系统,可以帮助开发者更方便地处理游戏对象上的事件。通过合理地配置EventTrigger,开发者可以实现各种各样的交互效果和游戏逻辑。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Unity中EventTrigger的几种使用方法](https://blog.csdn.net/qq_45152631/article/details/107388530)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [unity Behavior Designer 1.5.10 AI专用插件](https://download.csdn.net/download/qq_36848370/10389567)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [unity | EventTrigger(Button按钮按下、抬起等时执行的方法)](https://blog.csdn.net/weixin_49427945/article/details/127283331)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值