unity中通过拖拽,自定义scroll view中子物体顺序

1.在每个content的子物体上挂载DragHandler脚本,并且添加Canvs Group组件,设置见图

2.DragHandler脚本内容:

复制代码
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using System.Collections;

public class DragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    private RectTransform rectTransform;
    private Canvas canvas;
    private Transform parentTransform;
    private Vector2 startPosition;
    private int startSiblingIndex;
    private bool isDragging = false;

    private CanvasGroup canvasGroup;
    private int newIndex;
    private int top;//content的顶端间距
    private float spacing;//content的子物体的spacing
    private float height;//子物体的高度

    void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
        height = rectTransform.sizeDelta.y;
        canvas = GetComponentInParent<Canvas>();
        parentTransform = transform.parent;
        VerticalLayoutGroup layout = parentTransform.GetComponent<VerticalLayoutGroup>();
        top = layout.padding.top;
        spacing = layout.spacing;

        // 获取或添加 CanvasGroup 组件
        canvasGroup = GetComponent<CanvasGroup>();
        if (canvasGroup == null)
        {
            canvasGroup = gameObject.AddComponent<CanvasGroup>();
        }
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (eventData.button != PointerEventData.InputButton.Left) return;

        // 记录初始位置和索引
        startPosition = rectTransform.anchoredPosition;
        startSiblingIndex = transform.GetSiblingIndex();
        Debug.Log($"开始拖拽时:startSiblingIndex={startSiblingIndex}");
        // 禁用射线阻挡
        canvasGroup.blocksRaycasts = false;

        isDragging = true;
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!isDragging) return;

        // 更新位置(跟随鼠标)
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            parentTransform as RectTransform,
            eventData.position,
            canvas.worldCamera,
            out localPoint);

        rectTransform.anchoredPosition = new Vector2(startPosition.x, localPoint.y);

        // 直接更新顺序(不使用占位符)
        UpdateSortOrder();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (!isDragging) return;
        isDragging = false;

        // 恢复射线阻挡
        canvasGroup.blocksRaycasts = true;
        //标准化最终位置
        if(newIndex == 0)
        {
            rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, -(top+ height/2));
        }
        else
        {
            RectTransform preChildTrec = parentTransform.GetChild(newIndex - 1)?.GetComponent<RectTransform>();
            rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, preChildTrec.anchoredPosition.y - (spacing+height));
        }
    }

    // 直接更新排序顺序
    private void UpdateSortOrder()
    {
        newIndex = startSiblingIndex;

        // 计算当前拖拽物体在父物体局部空间中的位置
        Vector2 currentPos = rectTransform.anchoredPosition;
        Debug.Log($"自己的y:{currentPos.y}");

        // 遍历所有兄弟物体,找到合适的位置
        for (int i = 0; i < parentTransform.childCount; i++)
        {
            // 跳过自己
            if (parentTransform.GetChild(i) == transform) continue;

            RectTransform sibling = parentTransform.GetChild(i)?.GetComponent<RectTransform>();
            if (sibling != null)
            {
                Debug.Log($"子物体的名字:{sibling.name},y:{sibling.anchoredPosition.y}");
                // 简单的基于Y坐标的位置判断
                if (currentPos.y > sibling.anchoredPosition.y)
                {
                    newIndex = i;
                    // 如果新索引大于当前索引,需要减1,因为自己不在列表中
                    if (newIndex > transform.GetSiblingIndex())
                    {
                        newIndex--;
                    }
                    Debug.Log($"newIndex = {newIndex}");
                    break;
                }
            }
        }

        // 确保索引在有效范围内
        newIndex = Mathf.Clamp(newIndex, 0, parentTransform.childCount - 1);

        // 更新自己的位置
        if (newIndex != transform.GetSiblingIndex())
        {
            transform.SetSiblingIndex(newIndex);
        }
    }
}
相关推荐
小林up8 小时前
《Unity Shader入门精要》学习1:Phong 模型中法向量归一化的正确位置
学习·unity·游戏引擎
SmalBox15 小时前
【光照】[PBR][几何遮蔽]实现方法对比
unity·渲染
玉龙20251 天前
使用虚幻引擎时间轴制作一个弹跳小球
游戏引擎·虚幻·虚幻引擎基础入门
玉龙20251 天前
虚幻引擎|UE5制作DeepSeek插件并打包发布
ue5·游戏引擎·虚幻·虚幻引擎基础入门·=学习·虚幻引擎插件
万兴丶1 天前
Google Play合规指南:您的应用所使用的原生库不支持 16 KB 内存页面大小.快速解决
unity·google
SmalBox1 天前
【光照】[PBR][法线分布]为何不选Beckmann
unity·渲染
AA陈超2 天前
虚幻引擎UE5专用服务器游戏开发-21 连招技能动画蒙太奇播放
c++·游戏·ue5·游戏引擎·虚幻
一只一只2 天前
Unity 3D笔记——《B站阿发你好》
笔记·3d·unity
SmalBox3 天前
【光照】[PBR][法线分布]GGX实现方法对比
unity·渲染
UWA3 天前
游戏在高负载场景下,整机功耗控制在多少
游戏·unity·性能优化·游戏开发