Searcherパッケージの使い方

ShaderGraph等で使われている検索機能付きリストですが、Searcherという名前でパッケージ化されています。現状(4.9.2)パブリックな利用は推奨されていませんが、とても簡単に組み込めます。

まずはじめにプロジェクトへ Searcher パッケージを追加します。ShaderGraph 等が入っていると依存関係としてSearcherが自動的にインストールされますが、そうでない場合はPackageManager の「Add package by name」から「com.unity.searcher」を追加して下さい。

EditorWindowの作成

サンプルのベースとなるEditorWindowクラスを作ります。Searcherの表示にはEditorWindowが必須になります。ウインドウはメニューの「Window > Searcher Example」から開き、ボタンを押下したらSearcherが表示されるようにします。

using UnityEngine;
using UnityEditor;

class SearcherExample : EditorWindow
{
    [MenuItem("Window/Searcher Example")]
    static void Open()
    {
        GetWindow<SearcherExample>().Show();
    }

    void OnGUI()
    {
        if (GUILayout.Button("Open Searcher"))
        {
        }
    }
}

SearcherAdapterクラスの作成

Searcherをそのまま利用するとウインドウの横に詳細説明が表示されて邪魔なので、SearcherAdapterの派生クラスを追加して表示を無効化します。

オーバーライドしているHasDetailsPanelがそれです。

using UnityEngine;
using UnityEditor;
using UnityEditor.Searcher;

class ExampleAdapter : SearcherAdapter
{
    public override bool HasDetailsPanel => false;

    public ExampleAdapter(string title) : base(title)
    {
    }
}

class SearcherExample : EditorWindow
{
...

リストに表示する項目の作成

表示したい項目を作成します。項目はList<SearcherItem>で受け渡すのでそれで作ります。ツリー形式にする場合はSearcherItemのAddChildを使って子供を追加していきます。

SearcherTreeUtilityを使って自動化することも出来ますがここでは割愛します。

var items = new List<SearcherItem>();

var rootA = new SearcherItem("Root A");
items.Add(rootA);

rootA.AddChild(new SearcherItem("Child 1"));
rootA.AddChild(new SearcherItem("Child 2"));
rootA.AddChild(new SearcherItem("Child 3"));

var rootB = new SearcherItem("Root B");
items.Add(rootB);

var rootC = new SearcherItem("Root C");
items.Add(rootC);

コールバック関数の追加

項目を選択した際に呼び出されるコールバック関数を追加します。コールバック関数は項目を何も選択せずにウインドウを閉じた場合でも引数がNULLで呼ばれます。

この例では選択した項目をログに出力します。

bool OnSelect(SearcherItem selection)
{
    Debug.Log(selection);
    return true;
}

SearcherWindowの表示

あとはSearcherWindow.Showを呼び出して完了です。

表示位置の計算だけが少し特殊で、EditorWindowの左上からのオフセットになります。GUILayoutUtility でGUI座標をスクリーン座標に変換してからオフセットを計算しています。

var displayPos = GUIUtility.GUIToScreenPoint(GUILayoutUtility.GetLastRect().min) - position.min;
SearcherWindow.Show(this, items, new ExampleAdapter("Example"), OnSelect, displayPos, null);

これで完成。

検索機能が付いたツリー形式のセレクタが手に入りました。Searcherに関係する部分だけを見ると僅か数行です。

サンプルコード

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Searcher;

class ExampleAdapter : SearcherAdapter
{
    public override bool HasDetailsPanel => false;

    public ExampleAdapter(string title) : base(title)
    {
    }
}

class SearcherExample : EditorWindow
{
    [MenuItem("Window/Searcher Example")]
    static void Open()
    {
        GetWindow<SearcherExample>().Show();
    }

    void OnGUI()
    {
        if (GUILayout.Button("Open Searcher"))
        {
            var items = new List<SearcherItem>();

            var rootA = new SearcherItem("Root A");
            items.Add(rootA);

            rootA.AddChild(new SearcherItem("Child 1"));
            rootA.AddChild(new SearcherItem("Child 2"));
            rootA.AddChild(new SearcherItem("Child 3"));

            var rootB = new SearcherItem("Root B");
            items.Add(rootB);

            var rootC = new SearcherItem("Root C");
            items.Add(rootC);

            var displayPos = GUIUtility.GUIToScreenPoint(GUILayoutUtility.GetLastRect().min) - position.min;
            SearcherWindow.Show(this, items, new ExampleAdapter("Example"), OnSelect, displayPos, null);
        }
    }

    bool OnSelect(SearcherItem selection)
    {
        Debug.Log(selection);
        return true;
    }
}