
using System;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

using static ScrollViewUI.ScrollCycleView;

namespace ScrollViewUI
{

    public class ScrollCycleView
    {
        public enum DragType
        {
            Vertical,
            Horizontal

        }

        public class ItemData
        {


            public GameObject go;
            public RectTransform tran;
            public bool isActive;
        }

        public GameObject gameObject;
        /// <summary>
        /// 滑块的 rtf 控件
        /// </summary>
        public RectTransform rectTransform;
        /// <summary>
        /// 拖动的 ui tf;
        /// </summary>
        public RectTransform dragGOTran;

        /// <summary>
        /// 移动动画组件
        /// </summary>
        public UITweenSpring moveTween;

        public EventTrigger trigger;


        /// <summary>
        /// -拖动灵敏度（越大越灵敏）
        /// </summary>
        public float speed = 1;

        /// <summary>
        /// 滑动阻力（越大阻力越大）
        /// </summary>
        public float resistance = 1;

        /// <summary>
        /// 支持超框拖动
        /// </summary>
        public bool elastic = true;




        #region OnOpen参数
        public Scrollbar scrollBar;

        /// <summary>
        /// item的大小
        /// </summary>
        public Vector2 cellSize;
        public GameObject item;
        /// <summary>
        /// item的宽度加上 宽度间隔
        /// </summary>
        public float itemWidth;
        /// <summary>
        /// item的高度加上 高度度间隔
        /// </summary>
        public float itemHeight;

        /// <summary>
        /// 滑动类型
        /// </summary>
        public DragType dragType;
        /// <summary>
        /// 自动排布的行数或者列数 （竖的滑动列表 就表示  横着放多少个 换行 ，横的滑动列表 同理）
        /// </summary>
        public int fixedCount;
        /// <summary>
        ///  （如果 此时 是 竖 滑动条。 他就是 竖 这一列能放 几个 item数量【默认这个数量+1，表示总能显示全，且还能滚动时不漏空】。  横的滑动条同理）
        /// </summary>
        public int itemCount;
        /// <summary>
        /// 左右，上下间距
        /// </summary>
        public Vector2 spacing;

        /// <summary>
        ///  （竖的滑动列表 就表示 它的y值为  itemCount* itemHeight 一列竖的 占多长。 x值为0. 横的滑动条同理）
        /// </summary>
        public Vector2 offsetV2;


        public List<GameObject> goItemList = new List<GameObject>();
        /// <summary>
        ///  字典 物体
        /// </summary>
        public Dictionary<ItemData, int> goItemDataRefList = new Dictionary<ItemData, int>();
        /// <summary>
        /// 当前所有 循环的item       （ 竖 的滑动 条 时，  存储为：行 列）
        /// </summary>
        public List<List<ItemData>> cellItemList = new List<List<ItemData>>();



        #endregion

        #region SetData参数

        /// <summary>
        /// 显示所有的data 数量
        /// </summary>
        public int dataCount;

        public Action<int, GameObject> updateFunc;

        /// <summary>
        ///  grid的 RectTransform 滑动区间的值     = 竖 滑动条时，所有的行数* 一个item的高度   -    滑块的 rtf 控件的高度。
        /// </summary>
        public float itemDis;

        /// <summary>
        /// 滑动最大的 index 值 （最多滑动到那个 index）  = 竖 滑动条时：  值  （所有的行数 - 第一页的行数）
        /// </summary>
        public int maxOffset;

        public DGTween tmpTween;

        /// <summary>
        /// 当前 item的index （区间在  0 ———— （实际所有行数- 第一页的行数））
        /// （因为可以 通过当前ui  dragGOTran 滑动块移动的位置 ，算出 当前所在的item 的index）
        /// </summary>
        public int curDataIndex;

        #endregion


        public ScrollCycleView(Transform uiCanvas, Transform uiParent, DragType type)
        {
             this.Awake(uiCanvas, uiParent, type);
        }


    }
    public static class ScrollCycleViewSystem
    {



        public static void Awake(this ScrollCycleView self,Transform uiCanvas ,Transform tra, DragType type)
        {

            RectTransform trf = tra.GetComponent<RectTransform>();
            RectTransform trfSV = tra.Find("ScrollCycleView").GetComponent<RectTransform>();

            trfSV.anchoredPosition = Vector2.zero;



            Vector3[] arrWorldPos = new Vector3[4];

            float uiScale = uiCanvas.localScale.x;//canvs => unity坐标转换的比值    overlay =1  ， camra 具体来获取

            trf.GetWorldCorners(arrWorldPos);

            Vector3 worldSize = arrWorldPos[2] - arrWorldPos[0];

            trfSV.sizeDelta = worldSize / uiScale;




            self.InitComponent(trfSV.gameObject);



            var tmpScrollBar = tra.Find("Scrollbar");
            self.scrollBar = tmpScrollBar != null ? tmpScrollBar.GetComponent<Scrollbar>() : null;

            GridLayoutGroup layout = tra.Find("Layout").GetComponent<GridLayoutGroup>();
            layout.gameObject.SetActive(false);

            self.spacing = layout.spacing;


            self.item = layout.transform.GetChild(0).gameObject;
            self.item.GetComponent<RectTransform>().sizeDelta = layout.cellSize;
            self.item.gameObject.SetActive(true);
            self.dragType = type;
        }

        /// <summary>
        ///  初始化组件
        /// </summary>
        /// <param name="self"></param>
        /// <param name="goScroll">可以动态加载这个 goScroll 表示scroll</param>
        public static void InitComponent(this ScrollCycleView self, GameObject goScroll)
        {
            //这个滑动组件的系数
            self.speed = 1;
            self.resistance = 1;
            self.elastic = true;

            self.gameObject = goScroll;
            self.rectTransform = goScroll.transform.GetComponent<RectTransform>();
            self.dragGOTran = self.rectTransform.Find("grid").GetComponent<RectTransform>();

            //触发器
            self.trigger = goScroll.GetComponent<EventTrigger>();
            if (self.trigger == null) self.trigger = goScroll.AddComponent<EventTrigger>();

            self.trigger.RegisterEvent(EventTriggerType.BeginDrag, self.OnBeginDrag);
            self.trigger.RegisterEvent(EventTriggerType.EndDrag, self.OnEndDrag);
            self.trigger.RegisterEvent(EventTriggerType.Drag, self.OnDrag);


            //移动的动画组件
            self.moveTween = self.dragGOTran.GetComponent<UITweenSpring>();
            if (self.moveTween == null) self.moveTween = self.dragGOTran.gameObject.AddComponent<UITweenSpring>();
            self.moveTween.enabled = false;
            self.moveTween.OnUpdate = self.UpdatePosition;
            self.moveTween.OnMoveEnd = self.OnMoveEnd;
            self.moveTween.MomentumAmount = self.speed;
            self.moveTween.Strength = self.resistance;

        }
        /// <summary>
        ///  默认居中排列
        /// </summary>
        /// <param name="self"></param>
        /// <param name="fixedCount">默认自动填充 </param>
        public static void OnInit(this ScrollCycleView self, int fixedCount = -1)
        {

            self._OnOpen(self.gameObject, self.item, self.rectTransform.sizeDelta, self.dragType, self.spacing, fixedCount, self.scrollBar);
        }


        /// <summary>
        /// 设置 这个 滑动循环列表
        /// </summary>
        /// <param name="self"></param>
        /// <param name="goScroll">可以动态加载这个 goScroll 表示scroll</param>
        /// <param name="itemGO">滑动元素物体，他的锚点必须是一个点，</param>
        /// <param name="scrollBar">滑动滑条</param>
        /// <param name="scrollSizeDeltaV2">滑动区域大小（一般参数都是跟父节点大小一致）</param>
        /// <param name="dragType">滑动类型 横向，竖向</param>
        /// <param name="fixedCount">竖向时，他每一排 有几个元素，横向亦然</param>
        /// <param name="spacingV2">间距大小 </param>
        private static void _OnOpen(this ScrollCycleView self, GameObject goScroll, GameObject itemGO, Vector2 scrollSizeDeltaV2, DragType dragType, Vector2 spacingV2, int fixedCount = 1, Scrollbar scrollBar = null)
        {



            //self.InitComponent(goScroll);

            self.item = itemGO;
            self.scrollBar = scrollBar;
            self.rectTransform.sizeDelta = scrollSizeDeltaV2;
            self.dragType = dragType;

            self.spacing = spacingV2;

            self.cellSize = itemGO.GetComponent<RectTransform>().sizeDelta;
            self.itemWidth = self.spacing.x + self.cellSize.x;
            self.itemHeight = self.spacing.y + self.cellSize.y;


            //自动填满
            if (fixedCount == -1)
            {
                float len = self.dragType == DragType.Vertical ? self.rectTransform.sizeDelta.x + self.spacing.x : self.rectTransform.sizeDelta.y + self.spacing.y;

                fixedCount = self.dragType == DragType.Vertical ? ((int)(len / self.itemWidth)) : ((int)(len / self.itemHeight));
            }
            self.fixedCount = fixedCount;
            switch (self.dragType)
            {
                case DragType.Vertical:
                    // 设置 上测 为基准点
                    self.dragGOTran.anchorMin = new Vector2(0.5f, 1f);
                    self.dragGOTran.anchorMax = new Vector2(0.5f, 1f);
                    self.dragGOTran.pivot = new Vector2(0.5f, 1f);
                    // 设置 宽度为 
                    self.dragGOTran.sizeDelta = new Vector2(self.itemWidth * (self.fixedCount - 1), 0);
                    self.itemCount = Mathf.CeilToInt(scrollSizeDeltaV2.y / self.itemHeight + 1);
                    self.offsetV2 = new Vector2(0f, -self.itemHeight * self.itemCount);

                    break;
                case DragType.Horizontal:


                    self.dragGOTran.anchorMin = new Vector2(0f, 0.5f);
                    self.dragGOTran.anchorMax = new Vector2(0f, 0.5f);
                    self.dragGOTran.pivot = new Vector2(0f, 0.5f);
                    self.dragGOTran.sizeDelta = new Vector2(0f, self.itemHeight * (self.fixedCount - 1));
                    self.itemCount = Mathf.CeilToInt(scrollSizeDeltaV2.x / self.itemWidth + 1);
                    self.offsetV2 = new Vector2(self.itemWidth * self.itemCount, 0f);



                    break;
                default:
                    break;
            }

            self.goItemList.Clear();
            self.goItemDataRefList.Clear();
            self.cellItemList.Clear();

            //初始化 显示ui的 item 
            for (int j = 0; j < self.fixedCount; j++)
            {
                List<ItemData> itemList = new List<ItemData>();
                for (int i = 0; i < self.itemCount; i++)
                {
                    itemList.Add(new ItemData());
                }
                self.cellItemList.Add(itemList);
            }






        }


        /// <summary>
        ///  对应 数据 显示 刷新 这个滑动条  
        /// </summary>
        /// <param name="self"></param>
        /// <param name="dataCount"></param>
        /// <param name="updateFunc"></param>
        public static void SetData(this ScrollCycleView self, int dataCount, Action<int, GameObject> updateFunc)
        {
            // reset data
            self.dataCount = dataCount;
            self.updateFunc = updateFunc;
            self.goItemList.Clear();
            self.goItemDataRefList.Clear();



            //竖 或 横 滑动  对应的 竖 总数量。 或行总数亮 
            int VetiOrHoriTotalNum = Mathf.CeilToInt((float)self.dataCount / self.fixedCount);
            switch (self.dragType)
            {
                case DragType.Vertical:
                    self.itemDis = self.itemHeight * VetiOrHoriTotalNum + self.spacing.y - self.rectTransform.sizeDelta.y;

                    self.maxOffset = Mathf.Max(VetiOrHoriTotalNum - self.itemCount, 0);

                    break;
                case DragType.Horizontal:
                    self.itemDis = self.itemWidth * VetiOrHoriTotalNum + self.spacing.x - self.rectTransform.sizeDelta.x;
                    self.maxOffset = Mathf.Max(VetiOrHoriTotalNum - self.itemCount, 0);

                    break;
                default:
                    break;
            }


            self.SetBackTween();

            int oldIndex = self.curDataIndex;
            Vector2 oldPos = self.dragGOTran.anchoredPosition;

            self.curDataIndex = 0;
            self.SetPosition(Vector2.zero);

            //设置 滑动的对象ui
            float leftX = self.spacing.x / 2;
            float upY = self.spacing.y / 2;
            for (int j = 0; j < self.fixedCount; j++)
            {
                for (int i = 0; i < self.itemCount; i++)
                {
                    ItemData item = self.cellItemList[j][i];
                    int index = j + i * self.fixedCount;
                    //
                    if (item.go == null && index < self.dataCount)
                    {
                        GameObject go = GameObject.Instantiate(self.item);
                        go.name = "item" + index;
                        go.transform.SetParent(self.dragGOTran, false);
                        go.transform.localPosition = Vector3.zero;
                        go.SetActive(false);

                        RectTransform tran = go.GetComponent<RectTransform>();
                        tran.anchorMin = new Vector2(0, 1);
                        tran.anchorMax = new Vector2(0, 1);

                        item.go = go;
                        item.tran = tran;
                    }

                    //设置 初始位置 
                    if (item.go != null)
                    {
                        switch (self.dragType)
                        {
                            case DragType.Vertical:

                                item.tran.anchoredPosition = new Vector2(self.itemWidth * j, (0.5f - i - 1) * self.itemHeight + upY);
                                break;
                            case DragType.Horizontal:

                                item.tran.anchoredPosition = new Vector2((i + 0.5f) * self.itemWidth - leftX, -self.itemHeight * j);
                                break;
                            default:
                                break;
                        }



                        self.goItemList.Add(item.go);
                    }

                    self.SetUpdate(index, item);
                }
            }
            //设置 scrollBar
            if (self.scrollBar != null)
            {
                // 求出 初始页在总长的占比，得出 滑动块的尺寸（一页在总长的比例）
                switch (self.dragType)
                {
                    case DragType.Vertical:
                        //设置初始 一页占多少 ，总长度页（多少竖的item* itemHeight 去除最后一个item的间隔既为总长） 的 多少。
                        self.scrollBar.size = self.rectTransform.sizeDelta.y / (self.itemHeight * Mathf.CeilToInt((float)dataCount / self.fixedCount) + self.spacing.y);
                        break;
                    case DragType.Horizontal:

                        self.scrollBar.size = self.rectTransform.sizeDelta.x / (self.itemWidth * Mathf.CeilToInt((float)dataCount / self.fixedCount) + self.spacing.x);
                        break;
                    default:
                        break;
                }

                //求出 当前位置的 scrollbar 所在的 比例。
                if (oldIndex == 0)
                {
                    self.scrollBar.value = 0;
                }
                else
                {
                    switch (self.dragType)
                    {
                        case DragType.Vertical:

                            self.scrollBar.value = oldPos.y / self.itemDis;
                            break;
                        case DragType.Horizontal:

                            self.scrollBar.value = -oldPos.x / self.itemDis;
                            break;
                        default:
                            break;
                    }

                }


                self.scrollBar.onValueChanged.AddListener((f) =>
                {
                    //if (self.scrollBar.value <= 0 && f < 0) return;
                    //if (self.scrollBar.value >= 1 && f > 0) return;
                    Vector2 v2 = Vector2.zero;
                    int curIndex = 0;


                    switch (self.dragType)
                    {
                        case DragType.Vertical:

                            v2 = Vector2.Lerp(Vector2.zero, new Vector2(0, self.itemDis), f);
                            curIndex = Mathf.FloorToInt(v2.y / self.itemHeight);
                            break;
                        case DragType.Horizontal:

                            v2 = Vector2.Lerp(Vector2.zero, new Vector2(-self.itemDis, 0), f);
                            curIndex = Mathf.FloorToInt(-v2.x / self.itemWidth);
                            break;
                        default:
                            break;
                    }

                    self.SetPosition(v2);
                    self.SetItemIndex(curIndex);
                });
            }


            //设置 之前的位置 。
            if (oldIndex != 0)
            {
                if (self.itemDis > 0)
                {

                    switch (self.dragType)
                    {
                        case DragType.Vertical:

                            self.SetPosition(new Vector2(0, Mathf.Clamp(oldPos.y, 0, self.itemDis)));
                            break;
                        case DragType.Horizontal:

                            self.SetPosition(new Vector2(Mathf.Clamp(oldPos.x, -self.itemDis, 0), 0));
                            break;
                        default:
                            break;
                    }

                }
                self.SetItemIndex(oldIndex);
            }
        }






        //--设置当前索引位置在最上层，若duration > 0, 则播放动画缓动到指定位置, 否则立刻移动到指定位置（如果在滑动过程中 可能有 偏移问题）

        public static void SetIndex(this ScrollCycleView self, int curIndex = 0, float duration = 0, EaseType easeType = EaseType.Normal)
        {
            int itemOffset = Mathf.CeilToInt((float)curIndex / self.fixedCount) - 1;

            if (self.itemDis > 0)//滑动区间是否 能够翻页 能够翻页才 需要计算 设置idex
            {
                Vector2 av2 = self.dragGOTran.anchoredPosition;
                Vector2 mv2 = Vector2.zero;
                switch (self.dragType)
                {
                    case DragType.Vertical:
                        mv2 = new Vector2(0, Mathf.Clamp(self.itemHeight * itemOffset, 0, self.itemDis));
                        break;
                    case DragType.Horizontal:
                        mv2 = new Vector2(Mathf.Clamp(-self.itemWidth * itemOffset, -self.itemDis, 0), 0);
                        break;
                    default:
                        break;
                }



                if (duration > 0)
                {

                    DOTweenAnimCurve.Instance.To(0, 1, duration, progress =>
                    {
                        self.SetPosition(Vector2.Lerp(av2, mv2, progress));

                        int curIndexTmp;

                        switch (self.dragType)
                        {
                            case DragType.Vertical:
                                curIndexTmp = Mathf.FloorToInt(self.dragGOTran.anchoredPosition.y / self.itemHeight);
                                break;
                            case DragType.Horizontal:
                                curIndexTmp = Mathf.FloorToInt(-self.dragGOTran.anchoredPosition.x / self.itemWidth);
                                break;
                            default:
                                curIndexTmp = 0;
                                break;
                        }


                        self.SetItemIndex(curIndexTmp);

                        switch (self.dragType)
                        {
                            case DragType.Vertical:

                                if (self.scrollBar != null)
                                {
                                    self.scrollBar.value = self.dragGOTran.anchoredPosition.y / self.itemDis;
                                }
                                break;
                            case DragType.Horizontal:

                                if (self.scrollBar != null)
                                {
                                    self.scrollBar.value = -self.dragGOTran.anchoredPosition.x / self.itemDis;
                                }
                                break;
                            default:
                                break;
                        }


                    }).OnStart(() =>
                    {
                        self.trigger.enabled = false;
                    }).OnComplete(() =>
                    {
                        self.trigger.enabled = true;
                    }); ;


                }
                else
                {
                    if (self.curDataIndex > 0)//--初始化为0，不进行区域计算
                    {
                        foreach (var kvp in self.goItemDataRefList)//--检测到在可视区间内切换索引，记录原索引位置，保持切换后可视区域相对位置固定
                        {
                            if (kvp.Value == curIndex)
                            {
                                Vector2 kv2 = kvp.Key.tran.anchoredPosition + av2;
                                bool b = false;


                                switch (self.dragType)
                                {
                                    case DragType.Vertical:
                                        b = kv2.y > -self.rectTransform.sizeDelta.y - self.cellSize.y / 2 && kv2.y < self.cellSize.y / 2;
                                        break;
                                    case DragType.Horizontal:
                                        b = kv2.x > -self.cellSize.x / 2 && kv2.x < self.rectTransform.sizeDelta.x + self.cellSize.x / 2;
                                        break;
                                    default:
                                        break;
                                }

                                if (b)
                                {
                                    mv2 = av2;
                                    itemOffset = self.curDataIndex;
                                }
                                break;
                            }
                        }
                    }
                    self.SetPosition(mv2);




                    self.SetItemIndex(itemOffset);


                    switch (self.dragType)
                    {
                        case DragType.Vertical:

                            if (self.scrollBar != null)
                            {
                                self.scrollBar.value = self.dragGOTran.anchoredPosition.y / self.itemDis;
                            }
                            break;
                        case DragType.Horizontal:

                            if (self.scrollBar != null)
                            {
                                self.scrollBar.value = -self.dragGOTran.anchoredPosition.x / self.itemDis;
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
            else
            {

                self.SetPosition(Vector2.zero);
                self.SetItemIndex(0);
                if (self.scrollBar != null)
                {
                    self.scrollBar.value = 1;
                }
            }

        }


        /// <summary>
        /// 得到这个物体当前列表中的idx 
        /// </summary>
        /// <param name="self"></param>
        /// <param name="go"></param>
        /// <returns></returns>
        public static int GetItemDataIndex(this ScrollCycleView self, GameObject go)
        {
            foreach (var kvp in self.goItemDataRefList)
            {
                if (kvp.Key.go == go)
                {
                    return kvp.Value;
                }
            }

            return -1; // 如果没有找到匹配的项，可以根据需求返回适当的默认值
        }


        #region trigger 触发事件处理
        private static void OnBeginDrag(this ScrollCycleView self, BaseEventData data)
        {

            if (self.dataCount <= 0) return;
            self.SetBackTween(self.tmpTween);
            self.moveTween.enabled = true;
            self.moveTween.Momentum = Vector3.zero;
            self.moveTween.IsUseCallBack = false;
            self.moveTween.Strength = self.resistance;
            data.Use();
        }



        private static void OnDrag(this ScrollCycleView self, BaseEventData data)
        {

            if (self.dataCount <= 0) return;
            PointerEventData ped = data as PointerEventData;
            self.moveTween.LerpMomentum(ped.delta);
            self.UpdatePosition(ped.delta * self.speed);
            data.Use();
        }


        private static void OnEndDrag(this ScrollCycleView self, BaseEventData data)
        {

            if (self.dataCount <= 0) return;
            if (self.itemDis >= 0)
            {
                self.moveTween.IsUseCallBack = true;
            }
            else
            {
                self.OnMoveEnd();
            }
            data.Use();
        }

        private static void RegisterEvent(this EventTrigger trigger, EventTriggerType eventType, UnityAction<BaseEventData> callback, bool isRemoveAllEvent = true)
        {
            EventTrigger.Entry entry = null;
            bool isHas = false;
            // 查找是否已经存在要注册的事件
            foreach (EventTrigger.Entry existingEntry in trigger.triggers)
            {
                if (existingEntry.eventID == eventType)
                {
                    entry = existingEntry;
                    isHas = true;
                    break;
                }
            }

            // 如果这个事件不存在，就创建新的实例
            if (entry == null)
            {
                entry = new EventTrigger.Entry();
                entry.eventID = eventType;
            }
            if (isRemoveAllEvent)
                entry.callback.RemoveAllListeners();
            // 添加触发回调并注册事件
            entry.callback.AddListener(callback);
            if (!isHas)
                trigger.triggers.Add(entry);
        }

        #endregion


        #region 移动动画组件 
        /// <summary>
        /// 更新 拖拽的滑动区域 的 最新位置 
        /// </summary>
        /// <param name="self"></param>
        /// <param name="dv2">滑动区域绑定的 OnDrag 在 每一帧 移动的距离 间隔向量</param>
        private static void UpdatePosition(this ScrollCycleView self, Vector2 dv2)
        {


            Vector2 av2 = self.dragGOTran.anchoredPosition;
            //修正 参数 ，在竖滑动条 里  横向移动参数 置为0 . 横向滑动条同理
            switch (self.dragType)
            {
                case DragType.Vertical:
                    dv2.x = 0;
                    break;
                case DragType.Horizontal:
                    dv2.y = 0;
                    break;
                default:
                    break;
            }
            Vector2 fv2 = av2 + dv2;
            // 不允许超框拖拽的 处理   （把滑动数值 限定在可滑动区域）
            if (!self.elastic)
            {
                //可滑动
                if (self.itemDis > 0)
                {

                    switch (self.dragType)
                    {
                        case DragType.Vertical:
                            if (fv2.y < 0 || fv2.y > self.itemDis)
                            {
                                fv2.y = Mathf.Clamp(fv2.y, 0, self.itemDis);
                            }
                            break;
                        case DragType.Horizontal:
                            if (fv2.x > 0 || fv2.x < -self.itemDis)
                            {
                                fv2.x = Mathf.Clamp(fv2.x, -self.itemDis, 0);
                            }
                            break;
                        default:
                            break;
                    }

                }
                else
                {
                    fv2 = Vector2.zero;
                }
            }//允许超框的处理  （检测是否超框，若超框 则在滑动结束 ，把 延长滑动 动画 播放时间设为约等于0，直接调用 OnMoveEnd 播放回弹）
            else
            {
                if (self.itemDis > 0)
                {
                    bool isOutRange = false;
                    switch (self.dragType)
                    {
                        case DragType.Vertical:
                            isOutRange = (fv2.y < 0 && self.curDataIndex == 0) || (fv2.y > self.itemDis && self.curDataIndex == self.maxOffset);
                            break;
                        case DragType.Horizontal:
                            isOutRange = (fv2.x > 0 && self.curDataIndex == 0) || (fv2.x < -self.itemDis && self.curDataIndex == self.maxOffset);
                            break;
                        default:
                            break;
                    }


                    if (isOutRange)
                    {
                        self.moveTween.Strength = 999;
                    }
                }
            }
            self.SetPosition(fv2);


            int curIndex = 0;

            switch (self.dragType)
            {
                case DragType.Vertical:
                    curIndex = Mathf.FloorToInt(self.dragGOTran.anchoredPosition.y / self.itemHeight);
                    if (self.scrollBar != null)
                    {
                        self.scrollBar.value = self.dragGOTran.anchoredPosition.y / self.itemDis;
                    }
                    break;
                case DragType.Horizontal:
                    curIndex = Mathf.FloorToInt(-self.dragGOTran.anchoredPosition.x / self.itemWidth);
                    if (self.scrollBar != null)
                    {
                        self.scrollBar.value = -self.dragGOTran.anchoredPosition.x / self.itemDis;
                    }
                    break;
                default:
                    break;
            }

            self.SetItemIndex(curIndex);
        }

        private static void OnMoveEnd(this ScrollCycleView self)
        {
            Vector2 fv2 = self.dragGOTran.anchoredPosition;


            switch (self.dragType)
            {
                case DragType.Vertical:

                    if (self.itemDis < 0)
                    {

                        self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosY(self.dragGOTran, 0, 0.3f));
                    }
                    else
                    {
                        if (fv2.y < 0 && self.curDataIndex == 0)
                        {
                            self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosY(self.dragGOTran, 0, 0.3f));
                        }
                        else if (fv2.y > self.itemDis && self.curDataIndex == self.maxOffset)
                        {
                            self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosY(self.dragGOTran, self.itemDis, 0.3f));

                        }
                    }

                    break;
                case DragType.Horizontal:


                    if (self.itemDis < 0)
                    {
                        self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosX(self.dragGOTran, 0, 0.3f));

                    }
                    else
                    {
                        if (fv2.x > 0 && self.curDataIndex == 0)
                        {
                            self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosX(self.dragGOTran, 0, 0.3f));
                        }
                        else if (fv2.x < -self.itemDis && self.curDataIndex == self.maxOffset)
                        {
                            self.SetBackTween(DOTweenAnimCurve.Instance.DOAnchorPosX(self.dragGOTran, -self.itemDis, 0.3f));

                        }
                    }

                    break;
                default:
                    break;
            }

        }




        /// <summary>
        /// 设置 滑动的动画
        /// </summary>
        /// <param name="self"></param>
        /// <param name="tween"></param>
        private static void SetBackTween(this ScrollCycleView self, DGTween tween = null)
        {
            if (self.tmpTween != null)
            {
                DOTweenAnimCurve.Instance.KillAnimCurve(self.tmpTween);
                self.tmpTween = null;
            }

            self.tmpTween = tween;

        }

        /// <summary>
        /// 设置 滑动区间的 位置
        /// </summary>
        /// <param name="self"></param>
        /// <param name="v2"></param>
        private static void SetPosition(this ScrollCycleView self, Vector2 v2)
        {

            self.dragGOTran.anchoredPosition = v2;

        }
        /// <summary>
        /// 设置 某个item的激活信息以及回调
        /// </summary>
        /// <param name="self"></param>
        /// <param name="index">滑动条的某个item的 idex编号</param>
        /// <param name="item"></param>
        private static void SetUpdate(this ScrollCycleView self, int index, ItemData item)
        {
            if (index < self.dataCount)
            {
                //设置激活 
                if (!item.isActive)
                {
                    item.isActive = true;
                    item.go.SetActive(true);
                }
                //回调方法
                self.updateFunc(index, item.go);
                if (self.goItemDataRefList.ContainsKey(item))
                    self.goItemDataRefList[item] = index;
                else
                {
                    self.goItemDataRefList.Add(item, index);
                }
            }
            else
            {
                if (item.isActive)
                {
                    item.isActive = false;
                    item.go.SetActive(false);
                }
            }
        }




        /// <summary>
        ///  更新item 的位置 以及 信息
        /// </summary>
        /// <param name="self"></param>
        /// <param name="curIndex">当前 item的index()</param>
        private static void SetItemIndex(this ScrollCycleView self, int curIndex)
        {
            curIndex = Math.Clamp(curIndex, 0, self.maxOffset);
            if (curIndex != self.curDataIndex)
            {
                self.ItemListOffset(curIndex - self.curDataIndex);

                self.curDataIndex = curIndex;
            }



        }
        //在 lua中 负数 求余的  -1%10 = 9  .C# 中 -1%10 = -1；  C#来模拟 lua求余 -1%10 = -1%10+10 
        private static int Modulo(int dividend, int divisor)
        {
            int remainder = dividend % divisor;
            return remainder < 0 ? remainder + divisor : remainder;
        }
        /// <summary>
        /// 根据 移动 cellItemList 所在的列 数据 
        /// </summary>
        /// <param name="self"></param>
        /// <param name="list"></param>
        /// <param name="k"></param>
        private static void Move(this ScrollCycleView self, List<ItemData> list, int k)
        {

            k = Modulo(k, list.Count);

            if (k == 0)
                return;
            int endIdx = list.Count - 1;
            //反转 偏移的 那几个物体
            self.Reverse(list, 0, endIdx - k);
            //反转 后续的 那几个物体
            self.Reverse(list, list.Count - k, endIdx);
            //整体反转
            self.Reverse(list, 0, endIdx);
        }

        private static void Reverse(this ScrollCycleView self, List<ItemData> list, int start, int end)
        {
            while (start < end)
            {
                ItemData temp = list[start];
                list[start] = list[end];
                list[end] = temp;
                start++;
                end--;
            }
        }
        private static void ItemListOffset(this ScrollCycleView self, int offset)
        {
            int curNewDataIdx, offsetPage, offsetSomeOne, curChangeOffsetPage, showIdx, itemNextPage;
            ItemData item;

            //找出那几个 item需要 更新

            //竖滑动条时： 偏差了多少页（一页需要多少个item填满，总数/多少个Item，得出第几页）
            offsetPage = Mathf.FloorToInt(Mathf.Abs(offset) / self.itemCount);
            //竖滑动条时：偏差了第几个     1
            offsetSomeOne = Mathf.Abs(offset) % self.itemCount;

            if (offset > 0)
            {
                //ui的移动
                for (int j = 0; j < self.fixedCount; j++)
                {
                    for (int i = 0; i < self.itemCount; i++)
                    {
                        //当前item是否 翻到下一页。      
                        itemNextPage = (i + 1) <= offsetSomeOne ? 1 : 0;

                        curChangeOffsetPage = itemNextPage + offsetPage;
                        if (curChangeOffsetPage > 0)//那几个 item需要移动 （某个item他下次移动的位置，+x页的当前位置）
                        {

                            // 当前 的item 改变的多少页 * 一页列的数量 + 之前实际所在的 列 数量+  item排的序号 = 当前自己所处的 index
                            curNewDataIdx = self.itemCount * curChangeOffsetPage + self.curDataIndex + i;
                            //显示的具体idx  j表示第几列， + hang* 一行多少个   =  当前所处于的列数的上一列* 行数+当前所处的列数排第几个 
                            showIdx = curNewDataIdx * self.fixedCount + j;

                            //
                            item = self.cellItemList[j][i];
                            //这个item当前的位置 = 当前位置+ 移动了多少页的 插值
                            item.tran.anchoredPosition += self.offsetV2 * curChangeOffsetPage;


                            self.SetUpdate(showIdx, item);
                        }
                    }
                    //data数组 跟随 ui的 变动
                    self.Move(self.cellItemList[j], -offset);
                }
            }  //竖滑动时， 代表 向下 滑动
            else//竖滑动时， 代表 向上 滑动//竖滑动时， 代表 向上 滑动
            {
                for (int j = self.fixedCount - 1; j >= 0; --j)
                {
                    for (int i = self.itemCount - 1; i >= 0; --i)
                    {
                        //当前item是否 翻到上一页。      
                        itemNextPage = (i + 1) > (self.itemCount - offsetSomeOne) ? 1 : 0;

                        curChangeOffsetPage = itemNextPage + offsetPage;
                        if (curChangeOffsetPage > 0)
                        {
                            //当前 所在的idx 区间 
                            curNewDataIdx = self.curDataIndex + i - self.itemCount * curChangeOffsetPage;
                            //显示的idx = 
                            showIdx = curNewDataIdx * self.fixedCount + j;


                            item = self.cellItemList[j][i];
                            item.tran.anchoredPosition -= self.offsetV2 * curChangeOffsetPage;

                            self.SetUpdate(showIdx, item);
                        }
                    }
                    //data数组 跟随 ui的 变动
                    self.Move(self.cellItemList[j], -offset);
                }


            }


        }

















        #endregion



    }


}
