3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】AdvancedDropdownの使い方

Last updated at Posted at 2021-03-27

#概要

備忘録として、UnityEditorの機能であるAdvancedDropdownの使い方を記事にしておきます。
エディター拡張については詳しく説明しません。

今回は、AssetPathを表示、選択できるDropdownを作ります。

#AdvancedDropdownとは
AdvancedDropdownとはUnityEditorの機能で、ゲームオブジェクトのインスペクタに表示されているAddcomponentボタンを押したときに表示されるDropdownと同じものです。

#1.AdvancedDropdownを表示するためのクラスを作成
Sample.csとSampleEditor.csを作成します。
また、SampleEditorはEditor/~に作成します。

public class Sample : MonoBehaviour
{
}
[CustomEditor(typeof(Sample))]
public class SampleEditor : Editor
{
}

#2.AdvancedDropdownを継承したクラスを作成
すべてのアセットパスをDropdownとして表示する機能を作成します。
AdvacnedDropdownを使うには、UnityEditor.IMGUI.Controlsをusingします。


public class AssetPathDropdown : AdvancedDropdown
{
    private static readonly float MIN_LINE_COUNT = 15.0f;
    public event Action<string> onItemSelected = null;
    private Dictionary<int, string> pathDictionary = null;

    public AssetPathDropdown(AdvancedDropdownState state) : base(state)
    {
        pathDictionary = new Dictionary<int, string>();
        
        // 最小サイズを設定
        var minimumSize = this.minimumSize;
        minimumSize.y = MIN_LINE_COUNT * EditorGUIUtility.singleLineHeight;
        this.minimumSize = minimumSize;
    }

    protected override AdvancedDropdownItem BuildRoot()
    {
        var root = new AdvancedDropdownItem("AssetPath");

        foreach (var path in AssetDatabase.GetAllAssetPaths())
        {
            var splitStrings = path.Split('/');
            var parent = root;
            AdvancedDropdownItem lastItem = null;

            foreach (var str in splitStrings)
            {
                var foundChildItem = parent.children.FirstOrDefault(item => item.name == str);

                if (foundChildItem != null)
                {
                    // すでに同じ名前のAdvancedDropdownItemがあった場合は次へ
                    parent = foundChildItem;
                    lastItem = foundChildItem;
                    continue;
                }

                var child = new AdvancedDropdownItem(str);
                parent.AddChild(child);

                parent = child;
                lastItem = child;
            }

            if (lastItem != null)
            {
                // KeyをAdvacnedDropdownItemnのidにしてパスを取得できるようにする
                pathDictionary[lastItem.id] = path;
            }
        }

        return root;
    }

    protected override void ItemSelected(AdvancedDropdownItem item)
    {
        base.ItemSelected(item);
        onItemSelected?.Invoke(pathDictionary[item.id]);
    }
}

#3.SampleEditor.csを編集
Display dropdown buttonを押したときにDropdownを表示するようにします。そして、Dropdownの要素を選択したときにアセットパスをDebug.Logで出力するようにします。

AdvancedDropdownは内部的に表示されるので、IMGUIですがIMGUIContainerを使用しません。

[CustomEditor(typeof(Sample))]
public class SampleEditor : Editor
{
    private static readonly float BUTTON_WIDTH = 225.0f;
    private AssetPathDropdown sampleDropdown = null;

    public override VisualElement CreateInspectorGUI()
    {
        var root = new VisualElement();
        var button = new Button()
        {
            text = "Display Dropdown"
        };
        
        // ボタンの表示方法を設定
        button.style.width = BUTTON_WIDTH;
        button.style.alignSelf = Align.Center;
        button.style.color = Color.white;
        root.Add(button);

        sampleDropdown = new AssetPathDropdown(new AdvancedDropdownState());

        // イベント購読
        sampleDropdown.onItemSelected += OnItemSelected;
        button.clicked += () => OnClick(button.worldBound);

        return root;
    }

    private void OnClick(Rect rect)
    {
        sampleDropdown.Show(rect);
    }

    private void OnItemSelected(string path)
    {
        Debug.Log(path);
    }
}

#完成
image.png
image.png

##コード

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine.UIElements;

public class AssetPathDropdown : AdvancedDropdown
{
    private static readonly float MIN_LINE_COUNT = 15.0f;
    public event Action<string> onItemSelected = null;
    private Dictionary<int, string> pathDictionary = null;

    public AssetPathDropdown(AdvancedDropdownState state) : base(state)
    {
        pathDictionary = new Dictionary<int, string>();

        var minimumSize = this.minimumSize;
        minimumSize.y = MIN_LINE_COUNT * EditorGUIUtility.singleLineHeight;
        this.minimumSize = minimumSize;
    }

    protected override AdvancedDropdownItem BuildRoot()
    {
        var root = new AdvancedDropdownItem("AssetPath");

        foreach (var path in AssetDatabase.GetAllAssetPaths())
        {
            var splitStrings = path.Split('/');
            var parent = root;
            AdvancedDropdownItem lastItem = null;

            foreach (var str in splitStrings)
            {
                var foundChildItem = parent.children.FirstOrDefault(item => item.name == str);

                if (foundChildItem != null)
                {
                    parent = foundChildItem;
                    lastItem = foundChildItem;
                    continue;
                }

                var child = new AdvancedDropdownItem(str);
                parent.AddChild(child);

                parent = child;
                lastItem = child;
            }

            if (lastItem != null)
            {
                pathDictionary[lastItem.id] = path;
            }
        }

        return root;
    }

    protected override void ItemSelected(AdvancedDropdownItem item)
    {
        base.ItemSelected(item);
        onItemSelected?.Invoke(pathDictionary[item.id]);
    }
}

[CustomEditor(typeof(Sample))]
public class SampleEditor : Editor
{
    private static readonly float BUTTON_WIDTH = 225.0f;
    private AssetPathDropdown sampleDropdown = null;

    public override VisualElement CreateInspectorGUI()
    {
        var root = new VisualElement();
        var button = new Button()
        {
            text = "Display Dropdown"
        };

        button.style.width = BUTTON_WIDTH;
        button.style.alignSelf = Align.Center;
        button.style.color = Color.white;
        root.Add(button);

        sampleDropdown = new AssetPathDropdown(new AdvancedDropdownState());

        sampleDropdown.onItemSelected += OnItemSelected;
        button.clicked += () => OnClick(button.worldBound);

        return root;
    }

    private void OnClick(Rect rect)
    {
        sampleDropdown.Show(rect);
    }

    private void OnItemSelected(string path)
    {
        Debug.Log(path);
    }
}

#さいごに
この機能はUnityCsReferenceをみていたら偶然見つけました。あまり記事がないのと使い勝手が良さそうなので、備忘録として残しておきます。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?