当前位置: 首页 > 工具软件 > Awake.app > 使用案例 >

APP滑动翻页,嵌套滑动列表实现

贺宏富
2023-12-01

        双重滑动列表比较重要的点就是在于父子列表的滑动事件传递,不然在上的Scroll Rect会覆盖下层的,导致下层事件不响应。其次就是滑动后的页数位置判断,将UI能自动滑到对应的页数。

        首先来看最重要的事件传递,由于Scroll Rect没有自带可使用的滑动事件,于是我们就直接注册Unity的事件接口即可:

IBeginDragHandler, 鼠标按下时触发,
IDragHandler, 鼠标保持按下状态时会一直触发
IEndDragHandler 结束鼠标拖动,松开的时候会触发一次

这里有个坑注意一下,即使你只需要用到其中一个事件,也必须要有IDragHandle,不然不会触发滑动事件,具体代码实现如下:

public void OnBeginDrag(PointerEventData eventData)
    {
        PointerEventData pointerEventData = (PointerEventData)eventData;
        if (_thisScroll.horizontal)
        {   
            float angle = Mathf.Acos(Vector2.Dot(Vector2.up.normalized, pointerEventData.delta.normalized)) * Mathf.Rad2Deg; 
            if (angle < 45f || angle > 135f)
            {
                 pointerEventData.pointerDrag = _outsideScroll.gameObject;
                 _outsideScroll.OnBeginDrag(pointerEventData); 
            } 
            else
             { 
                pointerEventData.pointerDrag = _thisScroll.gameObject;  
                _thisScroll.OnBeginDrag(pointerEventData); 
            }
        }
        else if (_thisScroll.vertical)
        { 
            float angle = Mathf.Acos(Vector2.Dot(Vector2.right.normalized, pointerEventData.delta.normalized)) * Mathf.Rad2Deg; 
            if (angle < 45f || angle > 135f) 
            { 
                pointerEventData.pointerDrag = _outsideScroll.gameObject; 
                _outsideScroll.OnBeginDrag(pointerEventData); 
            } 
            else 
            { 
                pointerEventData.pointerDrag = _thisScroll.gameObject; 
                _thisScroll.OnBeginDrag(pointerEventData); 
            } 
        } 
        else 
        { 
            pointerEventData.pointerDrag = _outsideScroll.gameObject; 
            _outsideScroll.OnBeginDrag(pointerEventData);
        }
    }
    public void OnEndDrag(PointerEventData eventData) 
    {
        PointerEventData pointerEventData = (PointerEventData)eventData; 
        if (pointerEventData.pointerDrag == _outsideScroll.gameObject)
        {
            _outsideScroll.OnEndDrag(eventData);
        }
        else
        { 
            _thisScroll.OnEndDrag(eventData);
        } 
    }
    public void OnDrag(PointerEventData eventData) 
    { 
        PointerEventData pointerEventData = (PointerEventData)eventData;
        if (pointerEventData.pointerDrag == _outsideScroll.gameObject)
        {
            _outsideScroll.OnDrag(eventData);
        } 
        else 
        { 
            _thisScroll.OnDrag(eventData);
        } 
    }

主要逻辑就是通过开始拖拽事件判断角度,从而判断是横向滑动还是竖向滑动,并通向正确的Scroll Rect滑动事件。

然后外层挂载的滑动列表事件具体如下,主要是用来判断显示的页数,并自动滑到那一页。

            private ScrollRect rect;
            private List<float> posList = new List<float>();
            private int curIndex = -1;
            public float speed = 4;
            private bool _isDragging = false;
            public Action<int> onChildSelected = null;


            private void Awake()
            {
                ReferenceCollector referenceCollector = gameObject.GetComponent<ReferenceCollector>();

                rect = GetComponent<ScrollRect>();
                for (int i = 0; i < rect.content.transform.childCount; i++)
                {
                    posList.Add(i * (1.0f / (float)(rect.content.transform.childCount - 1)));
                }
            }

            private void Start()
            {
                PageTo(0);
            }

            private void Update()
            {
                if (curIndex >= 0 && !_isDragging)
                {
                    rect.horizontalNormalizedPosition = Mathf.Lerp(rect.horizontalNormalizedPosition,
                        posList[curIndex], Time.deltaTime * speed);
                }
            }

            public void OnBeginDrag(PointerEventData eventData)
            {
                _isDragging = true;
                rect.OnBeginDrag(eventData);
            }

            public void OnEndDrag(PointerEventData eventData)
            {
                rect.OnEndDrag(eventData);
                _isDragging = false;
                int index = 0;
                for (int i = 1; i < posList.Count; i++)
                {
                    if (Mathf.Abs(posList[i] - rect.horizontalNormalizedPosition) <
                        Mathf.Abs(posList[index] - rect.horizontalNormalizedPosition))
                    {
                        index = i;
                    }
                }

                PageTo(index);
            }

            public void OnDrag(PointerEventData eventData)
            {
                rect.OnDrag(eventData);
            }

            public void PageTo(int index)
            {
                if (curIndex != index)
                {
                    curIndex = index;
                    if (onChildSelected != null)
                    {
                        onChildSelected(curIndex);
                    }
                }
            }
        }

 类似资料: