Unity SnapScrollRect 滚动 匹配 列表 整页

展示效果


原理:

当停止滑动时

判断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;

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

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

        public float horizontalNormalizedPosition;

        public List values = new List();
        public List distances = new List();
        public List items = new List();

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

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

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

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

        /// 
        /// 回滚完毕后调用
        /// 
        public UnityEvent OnSnap;

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

        /// 
        /// 刷新数据,content的子物体数量变更时需要调用此函数
        /// 
        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());
                }
            }

            //累加的变量
            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();
        }


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

你可能感兴趣的:(unity,游戏引擎,ScrollRect,回滚)