tags: Unity uGUI C#
- unity 2018.4.2f1
- uGUIの
ScrollRect
(Scroll View)、VerticalLayoutGroup
、ContentSizeFitter
と併用するスクリプトコンポーネントです。
- 縦スクロールのリストビューにコンポーネントを追加することで、長押し+ドラッグ&ドロップで項目の並べ替えができるようになります。
- モード切替、ドラッグ開始、並び順更新、ドラッグ終了、項目の選択のコールバックを設定できます。
- スクリプトコンポーネントとして明示的に使用するのは、主に
ReOrderableList
とListElement
です。ListElement
は明示しない場合でも内部で使われます。ElementIndex
は主に内部で使用されるコンポです。
Tetr4labUtility
は、内部で使用されるユーティリティクラスです。Sample~
と命名されているアセットは必須ではありません。
- 動的リスト
- リストをスクリプトで生成する場合は、
SampleScene (dynamic)
をご覧ください。 - 対応するメインスクリプトは、
SampleDynamic
です。
- リストをスクリプトで生成する場合は、
- 静的リスト
- シーン上であらかじめリストを完成させておく場合は、
SampleScene (static)
をご覧ください。 - 対応するメインスクリプトは、
SampleStatic
です。
- シーン上であらかじめリストを完成させておく場合は、
- "Scroll View"を作ったら、以下の手順でマーカーを置きます。
- "ViewPort"の左下と右上にサイズ
(0, 0)
の空オブジェクトを置き、非アクティブにしてください。 - "Content"にも同じように空オブジェクトを置き、非アクティブにしてください。
- 非アクティブにしたくない場合は、
LayoutElement
を付けて、ignoreLayout
をチェックしてください。
- 非アクティブにしたくない場合は、
- "ViewPort"の左下と右上にサイズ
- "Scroll View"の"Content"に、
VerticalLayoutGroup
とContentSizeFitter
を付け、適切に設定してください。
VerticalLayoutGroup
のPadding
を大きく取ると、ドラッグ時にずれが生じます。
ScrollRect
と同じか直系尊属にあたるオブジェクトにReOrderableList
を付け、適切に設定します。
SampleScene
では、"Scroll View"の親オブジェクトに付けています。
`ReOrderableList`の設定内容
項目 | 説明 |
---|---|
ViewportMinMark | ScrollView/Viewportの左下に置かれたマーカーを指定します。 |
ViewportMaxMark | ScrollView/Viewportの右上に置かれたマーカーを指定します。 |
ContentMinMark | ScrollView/Contentの左下に置かれたマーカーを指定します。 |
ContentMaxMark | ScrollView/Contentの右上に置かれたマーカーを指定します。 |
LongPress | 長押しと判定する秒数を指定します。 |
AutoScrollSpeed | 範囲外へドラッグした際のスクロール速度を指定します。単位は適当です。 |
OnChangeMode | モード切替コールバックを設定できます。 |
OnSelect | 項目選択コールバックを設定できます。 |
OnBeginOrder | 並べ替え開始コールバックを設定できます。 |
OnUpdateOrder | 並べ替え更新コールバックを設定できます。 |
OnEndOrder | 並べ替え終了コールバックを設定できます。 |
- インスペクタでコールバック関数を割り当てる場合は、ダイナミックモードを使用する必要があります。(インスペクタ上で引数の指定ができてはダメです。)
- リストをスクリプトで生成する場合です。
- シーン上であらかじめリストを完成させておく場合は、「静的リストの場合」を参照してください。
ReOrderableList
クラスのインスタンスに対して、以降で説明する操作が可能です。- 生成したリスト項目は、
AddElement (~)
で配置してください。GameObject
1個を、あるいは、複数をGameObject []
やList<GameObject>
で、渡すことができます。- 項目を直接"Scroll View"に配置したり削除したりしてはいけません。
- 項目を一掃する場合は、
ClearElement ()
を使います。 - コールバックを指定するには以下のメソッドを使います。
- モード切替コールバックの登録
AddOnChangeModeListener ()
- モード切替コールバックの登録
RemoveOnChangeModeListener ()
- 項目選択コールバックの登録
AddOnSelectListener ()
- 項目選択コールバックの除去
RemoveOnSelectListener ()
- 並べ替え開始コールバックの登録
AddOnBeginOrderListener ()
- 並べ替え開始コールバックの除去
RemoveOnBeginOrderListener ()
- 並べ替え更新コールバックの登録
AddOnUpdateOrderListener ()
- 並べ替え更新コールバックの除去
RemoveOnUpdateOrderListener ()
- 並べ替え終了コールバックの登録
AddOnEndOrderListener ()
- 並べ替え終了コールバックの除去
RemoveOnEndOrderListener ()
- モード切替コールバックの登録
bool Interactable
を使うと、リストの応答性を切り替えられます。bool Orderable
で、現在ドラッグ可能モードかどうかを取得できます。List<int> Indexes
で、現在の並び順を取得できます。List<GameObject> GameObjects
で、現在の並び順の全項目オブジェクトを取得できます。GameObject [int]
(インデクサ)で、現在の並びから指定の項目オブジェクトを取得できます。
- シーン上であらかじめリストを完成させておく場合です。
- リストをスクリプトで生成する場合は、「動的リストの場合」を参照してください。
- 項目のオブジェクトに、
ListElement
とElementIndex
を付け、ElementIndex
にユニークなIndex
を指定してください。
- インスペクタでコールバック関数を割り当てる場合は、ダイナミックモードを使用する必要があります。(インスペクタ上で引数の指定ができてはダメです。)
- モード切替コールバックのAPIは、
void Action (bool)
で、引数はドラッグ可能かどうかです。 - 残り全てのコールバックは、
void Action (int)
で、引数は、対象になっている項目のIndex
、または見かけ上のSiblingIndex
です。
- 項目側でポインターイベントを取得して、使わない場合は親(
ScrollRect
)に投げています。 - ドラッグ中は、透明なダミーオブジェクトを生成して、項目と入れ替えています。
SiblingIndex
を使って、項目(とダミー)を並べ替えています。CanvasScaler
が動的にレイアウトした結果を得るために、マーカーオブジェクトを埋め込んで、位置と距離を取得しています。- ドラッグ中のポインタがスクロールの上下に外れたら、端からの距離に応じた速度でスクロールするようにしています。
- 横並び(
HolizontalLayoutGroup
)を使いたい。- この要求に配慮して極力
Vector2
で計算していますが、一部(ReOrderableList.UpdateDraggingPosition ()
など)が縦並びに依存しています。
- この要求に配慮して極力
- 6/13
- マルチタッチや、タッチとマウスの併用に関わる不具合を修正しました。
- 6/14
- モード切替のコールバックを用意して、UIデザインからの独立性を高めました。
- 当初は、完了ボタンやドラッグハンドルなどをリスト側で制御していました。
- 任意にリストの情報を取得する手段を拡充し、コールバックのAPIを簡素化しました。
- モード切替のコールバックを用意して、UIデザインからの独立性を高めました。
- 6/15
- 二本目以降の指には応じないようにしました。
- 2020/05/18
- 指摘をいただいて、未確定のドラッグ終了時の対象項目が二重に見える問題を修正しました。
- これは、ドラッグ中にリストに置かれたダミーオブジェクトが完全に除去される前に並び情報を取得したために、ダミーと本物の二つが列挙されたものです。
- 簡易にリストの取得を1フレーム遅らせることで回避しています。
- 「Unity-UI-Extensions」にその名も「Re-orderable List」というのがあるのですが、チラ見しただけで
面倒になって、自分の目的に合わないと断じて、ちゃんと見てません。つまり、これは車輪の再発明の可能性があります。