なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ

書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

2022/02/19

Unity の UXML で作成した独自のコントロールで、子要素を取得したい

カテゴリー:C#Unity

前回は UXML で独自のコントロールを作成しましたが、今回は子要素を取得していろいろやってみようと思います!
渡し方は Unity 公式ドキュメントで触れられている slot ではなく、単純に以下のような子要素 (ここでいう TabContent )となります。

<controls:Tab>
  <controls:TabContent title="全体設定">
    <!-- もっといっぱい... -->
  </controls:TabContent>
</controls:Tab>

ということで、やってみましょう。
まず、コントロールの UXML 側は以下のようになります。

<?xml version="1.0" encoding="utf-8"?>
<engine:UXML
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:engine="UnityEngine.UIElements"
  xmlns:editor="UnityEditor.UIElements"
  xsi:noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd">
</engine:UXML>

まぁ要するに何も無くても問題ありません。
Tab みたいな感じで、なんらかの描画を行いたい場合は、それを書いておくだけで OK です。
次は、 C# スクリプト側。

// ------------------------------------------------------------------------------------------
//  Copyright (c) Natsuneko. All rights reserved.
//  Licensed under the MIT License. See LICENSE in the project root for license information.
// ------------------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;

using UnityEditor.UIElements;

using UnityEngine.UIElements;

namespace NatsunekoLaboratory.VRAvatarToolkit.Controls
{
    public class Tab : VisualElement
    {
        private readonly VisualElement _container;

        public override VisualElement contentContainer => _container;

        public Tab()
        {
            // UXML 描画などは省略

            _container = new VisualElement();
            _container.AddToClassList("none"); 
            hierarchy.Add(_container);

            RegisterCallback<AttachToPanelEvent>(OnAttachToPanel);
        }

        private void OnAttachToPanel(AttachToPanelEvent e)
        {
            // write your code here...
        }

        public new class UxmlFactory : UxmlFactory<Tab, UxmlTraits> { }

        public new class UxmlTraits : VisualElement.UxmlTraits
        {
            public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
            {
                get { yield return new UxmlChildElementDescription(typeof(TabContent)); }
            }

            public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
            {
                base.Init(ve, bag, cc);
            }
        }
    }
}

ポイントは contentContainer を override して、自前で作成していることと、 UxmlTraits で許容する ChildElementsDescription の型を返していることです。
こうすることで、コンストラクタの最後に追加してある OnAttachToPanel イベントにて、 contentContainerChildren() を呼ぶと、今回の場合は TabContent の配列が返されます。
あとは、これを好きなところに追加したり、プロパティから値を引っぱってくるなりすれば、自前で子要素を受け取るコントロールの完成です!

ということで、今日のメモでした!