Unity SnapScrollRect 滚动 匹配 列表 整页

发布时间:2024年01月20日

展示效果


原理:

当停止滑动时

判断Contet的horizontalNormalizedPosition

与子Item的缓存值 相减,并得到最小值,然后将Content? horizontalNormalizedPosition滚动过去

使用方式:

直接将脚本挂到ScrollRect上

注意:在创建Content子物体时 或子物体数量变更,需要调用Refresh

代码:

namespace ShangShangQian.Component
{
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using System.Linq;
    using UnityEngine.Events;

    [RequireComponent(typeof(ScrollRect))]
    public class SnapScrollRect : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
    {
        private RectTransform content;
        private ScrollRect rect;

        /// <summary>
        /// content 的位置应该滚到什么
        /// </summary>
        public float target = 1;

        /// <summary>
        /// 回滚的速度 0-1 越小越快
        /// </summary>
        public float smooting = 0.25f;
        public float currentVelocity;

        public float horizontalNormalizedPosition;

        public List<float> values = new List<float>();
        public List<float> distances = new List<float>();
        public List<RectTransform> items = new List<RectTransform>();

        /// <summary>
        /// 是否拖拽中
        /// </summary>
        public bool isDrag = false;

        /// <summary>
        /// 到最近item的距离
        /// </summary>
        public float distanceMin;

        /// <summary>
        /// 到最近item的索引
        /// </summary>
        public int selectIndex;

        /// <summary>
        /// 是否匹配滑动中
        /// </summary>
        public bool Snaping = false;

        /// <summary>
        /// 回滚完毕后调用
        /// </summary>
        public UnityEvent<int> OnSnap;

        void Start()
        {
            rect = GetComponent<ScrollRect>();
            content = rect.content;
        }

        /// <summary>
        /// 刷新数据,content的子物体数量变更时需要调用此函数
        /// </summary>
        public void Refresh()
        {
            items.Clear();
            values.Clear();
            for (int i = 0; i < content.childCount; i++)
            {
                if (content.GetChild(i).gameObject.activeInHierarchy)
                {
                    items.Add(content.GetChild(i).GetComponent<RectTransform>());
                }
            }

            //累加的变量
            values.Add(0);
            //每一个格子的所占比多少  
            float v = 1f / (items.Count - 1);
            for (int i = 1; i < items.Count; i++)
            {
                values.Add(i * v);
            }

            //不同子元素数量 item 对应 的content  horizontalNormalizedPosition 数值
            //1  0  
            //2  0 1   
            //3  0 0.5 1
            //4  0 0.33 0.66 1
        }

        void Update()
        {
#if UNITY_EDITOR
            if (Input.GetKeyDown(KeyCode.A))
            {
                Refresh();
            }
#endif
        }

        void FixedUpdate()
        {
            horizontalNormalizedPosition = rect.horizontalNormalizedPosition;

            if (isDrag)
            {
                return;
            }

            if (Snaping)
            {
                rect.horizontalNormalizedPosition = Mathf.SmoothDamp(rect.horizontalNormalizedPosition, target, ref currentVelocity, smooting);
                if (Mathf.Abs(rect.horizontalNormalizedPosition - values[selectIndex]) < 0.001f)
                {
                    Snaping = false;
                    Debug.Log("回滚:" + selectIndex);
                    OnSnap.Invoke(selectIndex);
                }
            }

        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            isDrag = true;
        }

        public void OnDrag(PointerEventData eventData)
        {
            isDrag = true;
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            isDrag = false;

            Snaping = true;

            distances.Clear();

            //当松手后判断那个距离最近
            for (int i = 0; i < values.Count; i++)
            {
                distances.Add(Mathf.Abs(rect.horizontalNormalizedPosition - values[i]));
            }

            distanceMin = distances.Min();

            selectIndex = distances.FindIndex(b => b == distanceMin);
            target = values[selectIndex];
            rect.StopMovement();
        }


        /// <summary>
        /// 滚到到指定位置
        /// </summary>
        /// <param name="index"></param>
        public void SnapToIndex(int index)
        {
            Snaping = true;
            selectIndex = index;
            target = values[selectIndex];
        }
    }
}

文章来源:https://blog.csdn.net/qq_35030499/article/details/135721891
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。