【Unity】UIの順番を並び替える

投稿者: | 2021-02-02

画像を他の画像の上にドロップしたときに、2つの画像の順番を入れ替えてみました。また、画像をドラッグしている間に順番が詰まらないように、空いたところに透明な画像を差し込んでみます。

まず色が透明でRaycast Targetのチェックを切ったImageを、スクロールビューのContentの子にしてシーンに配置しておきました。

そして、UIをドラッグアンドドロップして並べ替えるときに、掴んだ画像のインデックスを覚えておいて、ドロップした時に使います。シーン上の透明画像をスクリプトにアタッチしておきます。

int index;
[SerializeField] Image emptyImage;

// Update()

foreach (RaycastResult target in results)
{
    // アイテム画像の時
    if (target.gameObject.tag == "ItemImage")
    {

        Goods goods = target.gameObject.GetComponent<Goods>();
        if (goods != null)
        {

            // クリック
            if (Input.GetMouseButtonDown(0))
            {
                // 掴んでいる状態にする
                isDragging = true;

                // アイテム画像のスクリプトを記憶
                currentImage = goods;

                // 掴んでいる画像にレイが当たらないようにする
                currentImage.SetRaycastTarget(false);

                // 親オブジェクトを記憶
                previousParent = goods.transform.parent;

                // ルートのCanvasを記憶
                currentParent = goods.transform.root;

                // Reference Resolutionを記憶
                referenceResolution = currentParent.GetComponent<CanvasScaler>().referenceResolution;

                // 画面サイズを記憶
                currentPixelRect = currentParent.GetComponent<Canvas>().pixelRect;

                // 順番を記憶
                index = goods.transform.GetSiblingIndex();

                // 透明画像をアクティブにする
                emptyImage.gameObject.SetActive(true);

                // 同じ位置に透明画像を置く
                emptyImage.transform.SetSiblingIndex(index);

                // アイテム画像をCanvasの子にする
                goods.transform.parent = currentParent;                         

            }
            // 他のアイテム画像にドロップしたとき
            else if (Input.GetMouseButtonUp(0) && isDragging)
            {
                // 掴んでいない状態にする
                isDragging = false;

                // 元の親の子に戻す
                currentImage.transform.parent = previousParent;

                // レイに当たるようにする
                currentImage.SetRaycastTarget(true);

                // 順番を入れ替える
                currentImage.transform.SetSiblingIndex(goods.transform.GetSiblingIndex());
                goods.transform.SetSiblingIndex(index);

                // 空にする
                currentImage = null;

                // 透明画像を非アクティブにする
                emptyImage.gameObject.SetActive(false);
            }
        }
    }else if(target.gameObject.tag == "DustBox")
    {
        // ...
    }
    else
    {
        // アイテム画像以外にドロップしたとき
        if (Input.GetMouseButtonUp(0) && isDragging)
        {
            // もとに戻す
            DropFail();
        }
    }
}           

透明画像は開始時に非アクティブにして、画像を掴んだ時にアクティブにします。ドロップしたときには非アクティブに戻します。

void Start()
{
    instance = this;
    pointer = new PointerEventData(EventSystem.current);

    // 透明画像を非アクティブにする
    emptyImage.gameObject.SetActive(false);
}

// ---
// Update()

// 順番を記憶
index = goods.transform.GetSiblingIndex();

// 透明画像をアクティブにする
emptyImage.gameObject.SetActive(true);

// 同じ位置に透明画像を置く
emptyImage.transform.SetSiblingIndex(index);

// ---


// 元に戻す
void DropFail()
{
    // 掴んでいない状態にする
    isDragging = false;

    // 空のとき終了
    if (currentImage == null) return;

    // 元の親の子に戻す
    currentImage.transform.parent = previousParent;

    // レイに当たるようにする
    currentImage.SetRaycastTarget(true);

    // 順番をもとに戻す
    currentImage.transform.SetSiblingIndex(index);

    // 空にする
    currentImage = null;

    // 透明画像を非アクティブにする
    emptyImage.gameObject.SetActive(false);
}

これで、アイテムを掴んでいるときはその場所に隙間ができるようになりました。

順番を入れ替えるときは、掴んでいる画像のSetSiblingIndexメソッドの引数に、ドロップした画像のインデックスを渡して、ドロップした画像では、記憶しておいたインデックスを渡します。

掴んでいる画像.transform.SetSiblingIndex(ドロップ先の画像.transform.GetSiblingIndex());
ドロップ先の画像.transform.SetSiblingIndex(記憶したインデックス);

また、どこかにドロップしたときや元に戻すときに、記憶したアイテム画像の変数にnullを入れて、再度元に戻そうとしたときに順番が変わらないようにしています。掴みながらメニューを閉じたときのために、掴んだ画像を元に戻すようにしています。

メニューを開閉すると順番が変わる
順番が変わらない

これでアイテムをドラッグアンドドロップで入れ替えられました。

コメントを残す

メールアドレスが公開されることはありません。