在原本的滑动列表上层创建一个相同的dragParentRect层,用来在拖拽时将GameObject置顶,创建一个空白的空物体用来占位,_parentRect就是滑动列表的Content。
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class EntryNodeGo : MonoBehaviour,IBeginDragHandler, IDragHandler, IEndDragHandler
{
public TMP_Text msg;
public Button editBtn;
public Button deleteBtn;
public GameObject blank;
private int _id;
private int _index;
private Vector2 _dragOffset;
private RectTransform _rectTransform;
private RectTransform _parentRect;
private RectTransform _dragParentRect;
private GameObject _blank;
private Vector2 _cellSize;
private Vector2 _spacing;
private RectOffset _padding;
private const int HorizontalCount = 4;
private void Start()
{
_rectTransform = transform as RectTransform;
_parentRect = transform.parent as RectTransform;
GridLayoutGroup gridLayoutGroup = _parentRect.GetComponent<GridLayoutGroup>();
_padding = gridLayoutGroup.padding;
_cellSize = gridLayoutGroup.cellSize;
_spacing = gridLayoutGroup.spacing;
}
public void Init(int id, int index,RectTransform dragParentRect)
{
_id = id;
_index = index;
_dragParentRect = dragParentRect;
msg.text = $"Entry {_id} \nindex {_index}";
}
public void OnBeginDrag(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
ExecuteEvents.ExecuteHierarchy(transform.parent.gameObject, eventData, ExecuteEvents.beginDragHandler);
}
else if (eventData.button == PointerEventData.InputButton.Right)
{
_index = transform.GetSiblingIndex();
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_dragParentRect, eventData.position, eventData.pressEventCamera, out var localPoint);
_dragOffset = (Vector2)_rectTransform.localPosition - localPoint;
_dragOffset.y += _parentRect.localPosition.y;
transform.SetParent(_dragParentRect, true);
_blank = Instantiate(blank,_parentRect);
_blank.transform.SetSiblingIndex(_index);
}
}
public void OnDrag(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
ExecuteEvents.ExecuteHierarchy(transform.parent.gameObject, eventData, ExecuteEvents.dragHandler);
}
else if (eventData.button == PointerEventData.InputButton.Right)
{
// 算出新的局部位置
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_dragParentRect, eventData.position, eventData.pressEventCamera, out var localPoint);
Vector2 newPos = localPoint + _dragOffset;
// 限制在父物体矩形范围内
Rect rect = _dragParentRect.rect;
Vector3 min = rect.min;
Vector3 max = rect.max;
// 考虑子物体自身尺寸
Vector2 halfSize = _rectTransform.rect.size * 0.5f;
newPos.x = Mathf.Clamp(newPos.x, min.x + halfSize.x, max.x - halfSize.x);
newPos.y = Mathf.Clamp(newPos.y, min.y + halfSize.y, max.y - halfSize.y);
_rectTransform.localPosition = newPos;
int horizontalIndex = (int)((newPos.x - _padding.left)/(_cellSize.x + _spacing.x));
float y = Mathf.Abs(newPos.y) + _cellSize.y/2;
int verticalIndex = Mathf.RoundToInt((y - _padding.top + _parentRect.localPosition.y)/(_cellSize.y + _spacing.y));
verticalIndex = Mathf.Max(1, verticalIndex);
_index = (verticalIndex - 1) * HorizontalCount + horizontalIndex;
_blank.transform.SetSiblingIndex(_index);
}
}
public void OnEndDrag(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
ExecuteEvents.ExecuteHierarchy(transform.parent.gameObject, eventData, ExecuteEvents.endDragHandler);
}
else if (eventData.button == PointerEventData.InputButton.Right)
{
Destroy(_blank);
transform.SetParent(_parentRect, true);
transform.SetSiblingIndex(_index);
}
}
}
滑动列表结构如下: