1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】IEventSystemHandlerの実行タイミング

Last updated at Posted at 2024-07-23

概要

UI (Image) に IDragHandler を持つコンポーネントが複数アタッチされており、それらの実行順番を制御したかった.

結論

GameObject に IEventSystemHandler を実装したコンポーネントが複数アタッチされている場合、それらの実行順はアタッチした順番(gameObject.GetComponents()で取得される並び)で決定される.

※自分は勘違いしていたが ExecutionOrder は関係ない.

OnDrag の実行タイミング

そもそも OnDrag()等がどのタイミングで実行されるのか把握していなかったため、
以下のログ出力を行うスクリプトで確認.

.cs
public class TestComponent : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {

    public RectTransform rect;

    //
    public void Update() => Debug.Log($"{Time.frameCount} Update");
    public void FixedUpdate() => Debug.Log($"{Time.frameCount} FixedUpdate");

    //
    public void OnBeginDrag(PointerEventData eventData) => Debug_.Log($"{Time.frameCount} OnBeginDrag", Colors.Red);
    public void OnEndDrag(PointerEventData eventData) => Debug_.Log($"{Time.frameCount} OnEndDrag", Colors.Red);

    public void OnDrag(PointerEventData eventData) {
        Debug_.Log($"{Time.frameCount} OnDrag", Colors.Orange);

        {   // マウス位置に追従させる
            Vector2 localPoint;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect.parent as RectTransform, eventData.position, eventData.pressEventCamera, out localPoint);
            rect.localPosition = localPoint;
        }
    }
}

【結果】
FixedUpdate() > OnBegineDrag() > OnDrag() > Update() の順に実行されている.
(おそらく MonoBehaviour の OnMouseXXX と同じタイミングで実行されている)

image.png

複数アタッチした時の実行順

DefaultExecutionOrder 設定による変化

コンポーネント A, B の DefaultExecutionOrder の値を入れ替えても実行順番に変化は無かった.

.cs
[DefaultExecutionOrder(-100)]
public class ExecutionOrderTestA{}

[DefaultExecutionOrder(100)]
public class ExecutionOrderTestB{}

コンポーネントのアタッチ順による変化

アタッチされている順番を入れ替えることで OnBeginDrag()/OnDrag()/OnEndDrag()の実行順番も逆になった.

image.png

調べてみると UnityEngine.EventSystems.ExecuteEvents が処理する際に、
普通に gameObject.GetComponets()で取得した順に処理しているようだった.

ExecuteEvents.cs
        /// <summary>
        /// Bubble the specified event on the game object, figuring out which object will actually receive the event.
        /// </summary>
        public static GameObject GetEventHandler<T>(GameObject root) where T : IEventSystemHandler
        {
            if (root == null)
                return null;

            Transform t = root.transform;
            while (t != null)
            {
                if (CanHandleEvent<T>(t.gameObject))
                    return t.gameObject;
                t = t.parent;
            }
            return null;
        }

        /// <summary>
        /// Whether the specified game object will be able to handle the specified event.
        /// </summary>
        public static bool CanHandleEvent<T>(GameObject go) where T : IEventSystemHandler{
            var internalHandlers = s_HandlerListPool.Get();
            GetEventList<T>(go, internalHandlers);
            var handlerCount = internalHandlers.Count;
            s_HandlerListPool.Release(internalHandlers);
            return handlerCount != 0;
        }

        /// <summary>
        /// Get the specified object's event event.
        /// </summary>
        private static void GetEventList<T>(GameObject go, IList<IEventSystemHandler> results)
        where T : IEventSystemHandler{
            // Debug.LogWarning("GetEventList<" + typeof(T).Name + ">");
            if (results == null)
                throw new ArgumentException("Results array is null", "results");

            if (go == null || !go.activeInHierarchy)
                return;

            var components = ListPool<Component>.Get();
            go.GetComponents(components);
            for (var i = 0; i < components.Count; i++){
                if (!ShouldSendToComponent<T>(components[i]))
                    continue;

                // Debug.Log(string.Format("{2} found! On {0}.{1}", go, s_GetComponentsScratch[i].GetType(), typeof(T)));
                results.Add(components[i] as IEventSystemHandler);
            }
            ListPool<Component>.Release(components);
            // Debug.LogWarning("end GetEventList<" + typeof(T).Name + ">");
        }

【参考】

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?