【Unity】【UI Toolkit】ScrollViewの要素をWrapする方法

UnityのUI ToolkitでScrollViewの要素をWrapする方法についてまとめました。

Unity 2021.3.25f1

やりたいこと

UI ToolkitのScrollViewは、デフォルトでは要素が一列に並びます。

要素が一列に並ぶ

いま、要素を横方向に並べつつ、横幅がいっぱいになったら次の列に並べ、さらに縦方向の要素がいっぱいになったらスクロールをするUIを作ることを考えます。

Wrap

方法

結論からいうと、以下の設定を行うことで上述の挙動を達成できます。

  1. ScrollViewの下にあるunity-content-containerを取得する
  2. 1.のFlex Directionをrowにする
  3. 1.のFlex Wrapをwrapにする

ただし、UI Builderからはunity-content-containerの設定を変更できないため、スクリプトあるいはUSSでこれを変更する必要があります。

次節からはそれらの方法について説明します。

その前に準備として、Scroll Viewを持つXMLを作っておきます。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <ui:ScrollView />
</ui:UXML>

さらにこれを表示するEditorWindowを作ります。
Scroll Viewの要素として赤いVisualElementを10個追加しておきます。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class Example : EditorWindow
{
    [SerializeField] private VisualTreeAsset _tree;
    
    [MenuItem("Window/Example")]
    public static void ShowWindow()
    {
        GetWindow<Example>();
    }
    
    private void OnEnable()
    {
        var root = rootVisualElement;
        _tree.CloneTree(root);
        
        var scrollView = root.Q<ScrollView>();

        // 要素を10個追加
        for (int i = 0; i < 10; i++)
        {
            var element = new VisualElement();
            element.style.backgroundColor = Color.red;
            // サイズを100x100に
            element.style.width = 100;
            element.style.height = 100;
            // マージンを5
            element.style.marginLeft = 5;
            element.style.marginRight = 5;
            element.style.marginTop = 5;
            element.style.marginBottom = 5;
            scrollView.contentContainer.Add(element);
        }
    }
}

このスクリプトのInspectorからTreeフィールドに先ほどのUXMLファイルをアサインし、Window > Exampleからウィンドウを開くと以下の結果が得られます。

準備

スクリプトで設定する

それではまずスクリプトFlex DirectionとFlex Wrapを設定します。
前節のEditorWindowを以下のように変更します。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class Example : EditorWindow
{
    [SerializeField] private VisualTreeAsset _tree;
    
    [MenuItem("Window/Example")]
    public static void ShowWindow()
    {
        GetWindow<Example>();
    }
    
    private void OnEnable()
    {
        var root = rootVisualElement;
        _tree.CloneTree(root);
        
        var scrollView = root.Q<ScrollView>();
        
        // Flex Direction: Row, Flex Wrap: Wrapに
        scrollView.contentContainer.style.flexDirection = FlexDirection.Row;
        scrollView.contentContainer.style.flexWrap = Wrap.Wrap;

        for (int i = 0; i < 10; i++)
        {
            var element = new VisualElement();
            element.style.backgroundColor = Color.red;
            element.style.width = 100;
            element.style.height = 100;
            element.style.marginLeft = 5;
            element.style.marginRight = 5;
            element.style.marginTop = 5;
            element.style.marginBottom = 5;
            scrollView.contentContainer.Add(element);
        }
    }
}

コメントの部分で設定を行っています。

USSで設定する

スクリプトではなくUSSで設定するには、まず以下のようなUSSファイルを作成します。

.unity-scroll-view__content-container {
    flex-direction: row;
    flex-wrap: wrap;
}

EditorWindowのスクリプトは以下のようにスタイルシートを適用するだけに変更します。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public sealed class Example : EditorWindow
{
    [SerializeField] private VisualTreeAsset _tree;
    [SerializeField] private StyleSheet _style;
    
    [MenuItem("Window/Example")]
    public static void ShowWindow()
    {
        GetWindow<Example>();
    }
    
    private void OnEnable()
    {
        var root = rootVisualElement;
        _tree.CloneTree(root);
        
        var scrollView = root.Q<ScrollView>();
        
        // スタイルシートを適用
        root.styleSheets.Add(_style);

        for (int i = 0; i < 10; i++)
        {
            var element = new VisualElement();
            element.style.backgroundColor = Color.red;
            element.style.width = 100;
            element.style.height = 100;
            element.style.marginLeft = 5;
            element.style.marginRight = 5;
            element.style.marginTop = 5;
            element.style.marginBottom = 5;
            scrollView.contentContainer.Add(element);
        }
    }
}

スクリプトのInspectorからStyleフィールドに先ほどのUSSファイルをアサインしておきます。

動作確認

上記の対応をした後にWindow > Exampleからウィンドウを開くと以下の結果が得られます。

動作確認

ScrollViewの要素をWrapできていることを確認できました。

参考

docs.unity3d.com