※ これは 2020/11/13 時点の Unity 2020.1.13f1 の情報です
最新版では動作が異なる可能性がありますのでご注意ください
前回の UI のドラッグ移動の続き
2つのドロップエリア間の移動はできたが、どの位置にドロップしても必ず最後の右端に挿入されるのが気に入らない
というわけで、ドロップ位置によって挿入位置が入れ替わるようにしてみた
スポンサードリンク
Hierarchy は一切手を付けず Draggable.cs
を下記のように変更
using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.EventSystems; [RequireComponent(typeof(CanvasGroup))] public class Draggable : MonoBehaviour { private Transform root; private Transform area; private Transform self; private CanvasGroup canvasGroup = null; public void Awake() { this.self = this.transform; this.area = this.self.parent; this.root = this.area.parent; this.canvasGroup = this.GetComponent<CanvasGroup>(); } public void OnBeginDrag(BaseEventData eventData) { // ドラッグできるよういったん DropArea の上位に移動する this.self.SetParent(this.root); // UI 機能を一時的無効化 this.canvasGroup.blocksRaycasts = false; } public void OnDrag(BaseEventData eventData) { this.self.localPosition = GetLocalPosition(((PointerEventData)eventData).position, this.transform); } private static Vector3 GetLocalPosition(Vector3 position, Transform transform) { // 画面上の座標 (Screen Point) を RectTransform 上のローカル座標に変換 RectTransformUtility.ScreenPointToLocalPointInRectangle( transform.parent.GetComponent<RectTransform>(), position, Camera.main, out var result); return new Vector3(result.x, result.y, 0); } public void OnEndDrag(BaseEventData eventData) { // ドロップ地点に DropAra があったらそこに入れる var dropArea = GetRaycastArea((PointerEventData)eventData); if (dropArea != null) { this.area = dropArea.transform; } // 挿入位置を x 座標から計算 var index = this.area.childCount; for (var i = 0; i < this.area.childCount; i++) { if (this.self.position.x < this.area.GetChild(i).position.x) { index = i; if (this.self.transform.GetSiblingIndex() < index) index--; break; } } this.self.SetParent(this.area); this.self.SetSiblingIndex(index); // UI 機能を復元 this.canvasGroup.blocksRaycasts = true; } /// <summary> /// イベント発生地点の DropArea を取得する /// </summary> /// <param name="eventData">イベントデータ</param> /// <returns>DropArea</returns> private static DropArea GetRaycastArea(PointerEventData eventData) { var results = new List<RaycastResult>(); EventSystem.current.RaycastAll(eventData, results); return results.Select(x => x.gameObject.GetComponent<DropArea>()) .FirstOrDefault(x => x != null); } }
変更したのは OnEndDrag()
の「挿入位置を x 座標から計算」のところあたり
ドロップエリアの子オブジェクトの x 座標を順に見ていって、ちょうといい位置に挿入されるように SetSiblingIndex()
に指定するインデックスを調整している感じ
お試し実行
よしよし並び替えできた