Unity滚动滑页的C#代码

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;

public class ScrollPage : MonoBehaviour, IBeginDragHandler, IEndDragHandler
{
    ScrollRect rect;
    //页面:0,1,2,3  索引从0开始
    //每页占的比列:0/3=0  1/3=0.333  2/3=0.6666 3/3=1
    //float[] pages = { 0f, 0.333f, 0.6666f, 1f };
    List<float> pages = new List<float>();
    int currentPageIndex = -1;

    //滑动速度
    public float smooting = 4;

    //滑动的起始坐标
    float targethorizontal = 0;

    //是否拖拽结束
    bool isDrag = false;
    
    float startime = 0f;
    float delay = 0.1f;
    
    void Start()
    {
        rect = transform.GetComponent<ScrollRect>();
        startime = Time.time;
    }
    
    void Update()
    {
        if (Time.time < startime + delay) return;
        UpdatePages();
        //如果不判断。当在拖拽的时候要也会执行插值,所以会出现闪烁的效果
        //这里只要在拖动结束的时候。在进行插值
        if (!isDrag && pages.Count>0)
        {
            rect.horizontalNormalizedPosition = 
                Mathf.Lerp(rect.horizontalNormalizedPosition, targethorizontal, Time.deltaTime * smooting);
        }
    }

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

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

        float posX = rect.horizontalNormalizedPosition;
        int index = 0;
        //假设离第一位最近
        float offset = Mathf.Abs(pages[index] - posX);
        for (int i = 1; i < pages.Count; i++)
        {
            float temp = Mathf.Abs(pages[i] - posX);
            if (temp < offset)
            {
                index = i;

                //保存当前的偏移量
                //如果到最后一页。反翻页。所以要保存该值,如果不保存。你试试效果就知道
                offset = temp;
            }
        }

        if(index!=currentPageIndex)
        {
            currentPageIndex = index;
        }
        
        targethorizontal = pages[index];
    }

    void UpdatePages()
    {
        // 获取子对象的数量
        int count = this.rect.content.childCount;
        int temp = 0;
        for(int i=0; i<count; i++)
        {
            if(this.rect.content.GetChild(i).gameObject.activeSelf)
            {
                temp++;
            }
        }
        count = temp;
        
        if (pages.Count!=count)
        {
            if (count != 0)
            {
                pages.Clear();
                for (int i = 0; i < count; i++)
                {
                    float page = 0;
                    if(count!=1)
                        page = i / ((float)(count - 1));
                    pages.Add(page);
                    //Debug.Log(i.ToString() + " page:" + page.ToString());
                }
            }
            OnEndDrag(null);
        }
    }
}
UIElasticScroll.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using LuaInterface;

namespace AQ
{
    [RequireComponent(typeof(ScrollRect))]
    public class UIElasticScroll : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
    {
        enum Dire
        {
            Horizontal,
            Vertical
        }

        Vector3 VECTOR_ONE = Vector3.one;

        [SerializeField]
        float startNormalized;
        [SerializeField]
        float endNormalized;

        bool isDrag;
        int targetIndex;

        ScrollRect scroll;
        [SerializeField]
        [Range(0, 100)]
        float smoothSpeed = 0.1f; // 弹性停靠的速度

        [SerializeField]
        [Range(0, 5)]
        int expandMoveCountMax = 1; // 边缘最多再移动多少个孩子的距离
        [SerializeField]
        [Range(-1, 1)]
        float oneChildStep = 0.3f; // 只有一个孩子时的滚动最大步长

        [SerializeField]
        Dire dire = Dire.Horizontal; // 滚动方向

        [SerializeField]
        AnimationCurve scaleCurve; // 孩子的尺寸大小与滚动中心的距离的关系

        LuaFunction dragHandler;
        LuaFunction endDragHandler;

        private void Start()
        {
            if (scroll == null)
            {
                scroll = GetComponent<ScrollRect>();
            }
            isDrag = false;
        }

        void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
        {

            isDrag = true;
        }

        void IDragHandler.OnDrag(PointerEventData eventData)
        {
            if (dragHandler!=null)
            {
                var centerIndex = CalTargetIndex();
                Debug.LogFormat("dragHandler.CallAndDispose: {0}", targetIndex);
                dragHandler.Call(centerIndex);
            }
        }

        void IEndDragHandler.OnEndDrag(PointerEventData eventData)
        {
            isDrag = false;

            targetIndex = CalTargetIndex();

            if (endDragHandler != null)
            {
                Debug.LogFormat("endDragHandler.CallAndDispose: {0}", targetIndex);
                endDragHandler.Call(targetIndex);
            }
        }

        int CalTargetIndex()
        {
            var contentChildCount = ContentChildCount;
            if (contentChildCount <= 1)
            {
                return 0;
            }

            var step = (endNormalized - startNormalized) / (contentChildCount - 1);
            var curNormalizedValue = CurNormalized;

            if ((endNormalized - startNormalized > 0 && curNormalizedValue < startNormalized)
                || (endNormalized - startNormalized <= 0 && curNormalizedValue > startNormalized))
            {
                return 0;
            }
            if ((endNormalized - startNormalized > 0 && curNormalizedValue > endNormalized)
                || (endNormalized - startNormalized <= 0 && curNormalizedValue < endNormalized))
            {
                return contentChildCount - 1;
            }

            var criticalDist = Mathf.Abs(step / 2);
            for (int index = 0; index < contentChildCount; index++)
            {
                var dist = (startNormalized + step * index) - curNormalizedValue;
                dist = Mathf.Abs(dist);
                if (dist <= criticalDist)
                {
                    return index;
                }
            }

            // will not to here
            return 0;
        }

        private void Update()
        {
            if (isDrag)
            {
                Constraint();
            }
            else
            {
                Elastic();
            }
            ScaleChild();
        }

        void Constraint()
        {
            var contentChildCount = ContentChildCount;
            if (contentChildCount < 1)
            {
                SetNormalized(startNormalized);
                return;
            }

            var curNormalizedValue = CurNormalized;
            var step = contentChildCount == 1 ? oneChildStep : (endNormalized - startNormalized) / (contentChildCount - 1);

            var startConstraint = startNormalized + step * -1;
            var endConstraint = endNormalized + step * 1;

            var min = startConstraint <= endConstraint ? startConstraint : endConstraint;
            var max = startConstraint <= endConstraint ? endConstraint : startConstraint;

            var constraintValue = Mathf.Clamp(curNormalizedValue, min, max);
            SetNormalized(constraintValue);
        }

        void Elastic()
        {
            var contentChildCount = ContentChildCount;
            if (contentChildCount <= 1)
            {
                SetNormalized(startNormalized);
                return;
            }

            if (targetIndex < 0 || targetIndex > contentChildCount - 1)
            {
                targetIndex = 0;
            }

            var step = (endNormalized - startNormalized) / (contentChildCount - 1);
            var targetNormalized = startNormalized + step * targetIndex;

            var curNormalizedValue = CurNormalized;
            var ratio = Mathf.Clamp01(smoothSpeed * Time.deltaTime);
            var normalizeValue = Mathf.Lerp(curNormalizedValue, targetNormalized, ratio);
            SetNormalized(normalizeValue);
        }

        void ScaleChild()
        {
            var contentChildCount = ContentChildCount;
            if (scaleCurve == null || contentChildCount == 0)
            {
                return;
            }

            var curNormalizedValue = CurNormalized;
            if (contentChildCount == 1)
            {
                var child = GetChild(0);
                if (child)
                {
                    child.localScale = VECTOR_ONE * scaleCurve.Evaluate(0f);
                }
                return;
            }

            var step = (endNormalized - startNormalized) / (contentChildCount - 1);
            for (int childIndex = 0; childIndex < contentChildCount; childIndex++)
            {
                var child = GetChild(childIndex);
                if (child)
                {
                    var childNormalized = startNormalized + step * childIndex;
                    var dist = Mathf.Abs(childNormalized - curNormalizedValue);
                    if (step != 0)
                    {
                        dist = Mathf.Abs(dist / step);
                    }
                    var scaleRatio = scaleCurve.Evaluate(dist);
                    child.localScale = VECTOR_ONE * scaleRatio;
                }
            }
        }

        Transform GetChild(int childIndex)
        {
            var contentTran = scroll.content.transform;
            var allCount = contentTran.childCount;
            var curIndex = -1;
            for(int i = 0; i < allCount; i++)
            {
                var child = contentTran.GetChild(i);
                if (child.gameObject.activeSelf && ++curIndex==childIndex)
                {
                    return child;
                }
            }
            return null;
        }

        int ContentChildCount
        {
            get
            {
                if (scroll.content)
                {
                    var contentTran = scroll.content.transform;
                    var allCount = contentTran.childCount;
                    var realCount = 0;
                    for(int i = 0; i < allCount; i++)
                    {
                        if (contentTran.GetChild(i).gameObject.activeSelf)
                        {
                            realCount++;
                        }
                    }
                    return realCount;
                }
                else
                {
                    return 0;
                }
            }
        }

        float CurNormalized
        {
            get
            {
                return dire == Dire.Horizontal ? scroll.horizontalNormalizedPosition : scroll.verticalNormalizedPosition;
            }
        }

        void SetNormalized(float value)
        {
            if (dire == Dire.Horizontal)
            {
                scroll.horizontalNormalizedPosition = value;
            }
            else
            {
                scroll.verticalNormalizedPosition = value;
            }
        }

        public bool CheckIsDraging()
        {
            return isDrag;
        }

        public void SetTargetIndex(int value)
        {
            targetIndex = value;
        }

        public int GetTargetIndex()
        {
            return isDrag ? -1 : targetIndex;
        }

        public void AddDragListener(LuaFunction handler)
        {
            dragHandler = handler;
        }

        public void AddEndDragListener(LuaFunction handler)
        {
            endDragHandler = handler;
        }

        private void OnDestroy()
        {
            RemoveListener();
        }

        public void RemoveListener()
        {
            if (dragHandler != null)
            {
                dragHandler.Dispose();
            }
            if(endDragHandler != null)
            {
                endDragHandler.Dispose();
            }
            dragHandler = null;
            endDragHandler = null;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kerven_HKW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值