2
4

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】 UITKのUIElementsのイベントをR3で扱う

Posted at

今回の目的

  • UITKのUIElementのイベントをR3のObservableで受け取れるようにしたい。

定義した拡張メソッド

ButtonINotifyValueChanged<T>に拡張メソッドを定義すればひとまずイベントは取れそう。

using System;
using System.Threading;
using R3;
using UnityEngine.UIElements;

namespace R3Extensions
{
    public static class R3UitkExtensions
    {
        public static Observable<Unit> OnClickAsObservable(this Button button, CancellationToken token = default)
        {
            return Observable.FromEvent(
                e => button.clicked += e,
                e => button.clicked -= e, token);
        }

        public static Observable<T> OnValueChangedAsObservable<T>(this INotifyValueChanged<T> changed,
            CancellationToken token = default)
        {
            if (changed is CallbackEventHandler handler)
            {
                return Observable.FromEvent<EventCallback<ChangeEvent<T>>, T>(
                    convert => evt => convert(evt.newValue),
                    add => handler.RegisterCallback(add),
                    remove => handler.UnregisterCallback(remove),
                    token
                );
            }

            throw new ArgumentException($"{changed} does not implement CallbackEventHandler.");
        }
    }
}

使用例

using R3;
using R3Extensions; // here
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace Sandbox
{
    public class UIControlSample : MonoBehaviour
    {
        [SerializeField] private UIDocument _uiDocument;

        void Start()
        {
            // 各種UIElementを作成してUIに追加する

            var button = new Button();
            _uiDocument.rootVisualElement.Add(button);

            var dropdown = new DropdownField();
            dropdown.choices.Add("Option 1");
            dropdown.choices.Add("Option 2");
            dropdown.choices.Add("Option 3");
            _uiDocument.rootVisualElement.Add(dropdown);

            var textField = new TextField
            {
                value = "Initial Text"
            };
            _uiDocument.rootVisualElement.Add(textField);

            var toggle = new Toggle("Toggle Me");
            _uiDocument.rootVisualElement.Add(toggle);

            var slider = new Slider("Slide Me", 0, 100);
            _uiDocument.rootVisualElement.Add(slider);

            var colorField = new ColorField("Pick a Color")
            {
                value = Color.red
            };
            _uiDocument.rootVisualElement.Add(colorField);

            var layerMaskField = new LayerMaskField("Select Layer Mask")
            {
                value = LayerMask.GetMask("Default")
            };

            _uiDocument.rootVisualElement.Add(layerMaskField);

            // --- ここからイベント購読 ---

            // Button
            button.OnClickAsObservable(destroyCancellationToken)
                .Subscribe(_ => Debug.Log("Button clicked!"))
                .AddTo(this);

            // Dropdown
            dropdown.OnValueChangedAsObservable(destroyCancellationToken)
                .Subscribe(x => Debug.Log($"Dropdown changed: {x}, Index: {dropdown.index}"))
                .AddTo(this);

            // TextField
            textField.OnValueChangedAsObservable()
                .Subscribe(x => Debug.Log($"TextField changed: {x}"))
                .AddTo(this);

            // Toggle
            toggle.OnValueChangedAsObservable()
                .Subscribe(isOn => Debug.Log($"Toggle is now: {isOn}"))
                .AddTo(this);

            // Slider
            slider.OnValueChangedAsObservable()
                .Subscribe(value => Debug.Log($"Slider value changed: {value}"))
                .AddTo(this);

            // ColorField and LayerMaskField
            colorField.OnValueChangedAsObservable()
                .Subscribe(color => Debug.Log($"Color changed: {color}"))
                .AddTo(this);

            // LayerMaskField
            layerMaskField.OnValueChangedAsObservable()
                .Subscribe(mask => Debug.Log($"Layer Mask changed: {mask}"))
                .AddTo(this);

            // etc...
        }
    }
}

所感

  • UIElementは基本的にINotifyValueChanged<T>を実装しており、ここからイベントを取得することができる
    • ただしButtonclickedイベントは別扱いだった
  • uGUIのInputFieldにあったonEditEndのイベントはUITKでは取れない?
    • Unity6.0以降では IEditableElement というインタフェースが追加されているっぽくここから将来的に取れるかも
      • しかしinternalなためアクセスはできず、ScriptReferenceにもまだ書かれていない
2
4
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
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?