| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888 | using System;using System.Collections.Generic;using Fort23.Core;using Fort23.Mono;using Fort23.UTool;using UnityEngine;using UnityEngine.UI;public class ScrollList : MonoBehaviour, IScrollListContent{    public enum LayoutType    {        Left,        Center,    }    // public Camera Camera;    public ScrollRect ScrollRect;    public Vector2 ScrollRectSizedata;    public Vector2Int Page = new Vector2Int(1, 1);    public float bottom;    public RectTransform wdiget;    public Vector2 sizeData = new Vector2();    public List<IScorllListWidget> hindWidget = new List<IScorllListWidget>();    public List<IScorllListWidget> showWidget = new List<IScorllListWidget>();    protected int currIndex;    // public Vector2 offSize;    public bool isCustomizeHeight;    public Vector2 posOff;    public bool isDelay;    public long delayTime;    public bool isAdaptationWidth;    private bool _isStartDelay;    private bool hasAddedOffset = false;    protected IScrollListContent m_scrollListContent;    // private void Awake()    // {    //     Init(this, 100);    // }    protected RectTransform myRectTransform;    private float addY;    protected int m_startIndex;    private int _maxSize;    private Vector3 onePos;    private CTask isAwaitInitFinis;    private bool _isBreak;    private Vector2 _vel;    public LayoutType layoutType = LayoutType.Left;    public float overflowDistance;    private void Awake()    {        if (myRectTransform == null)        {            myRectTransform = gameObject.GetComponent<RectTransform>();        }        onePos = myRectTransform.localPosition;    }    public void Break()    {        _isBreak = true;    }    public void Clear()    {        currIndex = 0;        IScorllListWidget[] listWidgets = showWidget.ToArray();        for (int i = 0; i < listWidgets.Length; i++)        {            HindIWidget(listWidgets[i]);        }        showWidget.Clear();        ScrollRect.content.localPosition = onePos;        ScrollRect.StopMovement();    }    /// <summary>    /// 初始化    /// </summary>    /// <param name="scrollListContent"></param>    /// <param name="maxSize"></param>    /// <param name="startIndex"></param>    public async CTask Init(IScrollListContent scrollListContent, int maxSize, int startIndex = 0, bool t = false)    {        if (startIndex < 0)        {            startIndex = 0;        }        if (ScrollRect == null)        {            ScrollRect = transform.GetComponentInParent<ScrollRect>(true);        }        RectTransform root = ScrollRect.GetComponent<RectTransform>();        addY = 0;        _isBreak = true;        using (await CoroutineLockComponent.Instance.Wait(this.GetInstanceID().ToString()))        {            if (myRectTransform == null)            {                myRectTransform = gameObject.GetComponent<RectTransform>();            }            Clear();            _maxSize = maxSize;            if (isAdaptationWidth)            {                ScrollRect.SetLayoutHorizontal();                await TimerComponent.Instance.WaitAsync(50);                float fx = ((root.rect.size.x - posOff.x) / sizeData.x);                int c = (int)fx;                if (fx % 1 >= 0.9f)                {                    c += 1;                }                Page.y = c;            }            if (layoutType == LayoutType.Center)            {                await TimerComponent.Instance.WaitAsync(30);                float w = root.rect.width / 2;                posOff = new Vector2(w, posOff.y);            }            await TimerComponent.Instance.WaitAsync(10);            Vector2 lasetPos = myRectTransform.anchoredPosition;            if (ScrollRect.horizontal)            {                myRectTransform.sizeDelta = new Vector2(sizeData.x * startIndex, myRectTransform.sizeDelta.y);                myRectTransform.anchoredPosition =                    new Vector2(sizeData.x * startIndex * -1, myRectTransform.anchoredPosition.y);                lasetPos = myRectTransform.anchoredPosition;                m_startIndex = 0;                currIndex = startIndex;            }            else if (ScrollRect.vertical)            {                // m_startIndex = startIndex;                currIndex = startIndex;                // Vector2 targetSizeDelta = CalculateTargetSizeDelta(startIndex);                Vector2 targetSizeDelta;                if (t)                {                    targetSizeDelta = CalculateBottomSizeDelta(maxSize);                }                else                {                    targetSizeDelta = CalculateBottomSizeDelta(startIndex);                }                targetSizeDelta += new Vector2(0, bottom);                lasetPos = CalculateTargetPosition(startIndex);                myRectTransform.sizeDelta = new Vector2(sizeData.x, targetSizeDelta.y);            }            _isBreak = false;            m_scrollListContent = scrollListContent;            CTaskAwaitBuffer cTaskAwaitBuffer = new CTaskAwaitBuffer();            CTask<IScorllListWidget> ctask = Cread(currIndex, false);            cTaskAwaitBuffer.AddTask(ctask);            currIndex++;            if (isDelay)            {                _isStartDelay = true;            }            await cTaskAwaitBuffer.WaitAll();            ScrollRect.SetLayoutVertical();            myRectTransform.anchoredPosition = lasetPos;            ScrollRect.StopMovement();            await onValueChanged(Vector2.zero, true);            ScrollRect.onValueChanged.RemoveListener(onValueChanged2);            ScrollRect.onValueChanged.AddListener(onValueChanged2);            _isStartDelay = false;        }    }    public void RemoveWidget(IScorllListWidget listWidget)    {        bool isHide = false;        for (int i = 0; i < showWidget.Count; i++)        {            if (showWidget[i] == listWidget || isHide)            {                isHide = true;                HindIWidget(showWidget[i]);                i--;            }        }        if (isHide)        {            if (showWidget.Count <= 0)            {                currIndex = 0;                CTask<IScorllListWidget> ctask = Cread(currIndex, false);                currIndex++;            }            onValueChanged(Vector2.zero, false);        }    }    private void Update()    {        if (Input.GetKeyDown(KeyCode.Y))        {            HindWidget();        }    }    protected async CTask<IScorllListWidget> Cread(int index, bool isUp)    {        int showIndex = index - m_startIndex;        if (showWidget.Count > 100)        {            return null;        }        IScorllListWidget widget = await GetWidget(index);        if (widget == null)        {            return null;        }        showWidget.Add(widget);        int xoff = 0;        int yoff = 0;        if (ScrollRect.horizontal)        {            xoff = showIndex / Page.x;            yoff = showIndex % Page.x;        }        else if (ScrollRect.vertical)        {            if (showIndex >= 0 || isCustomizeHeight)            {                yoff = showIndex / Page.y;                xoff = showIndex % Page.y;            }            else            {                {                    xoff = showIndex % (Page.y + 1);                    yoff = showIndex / (Page.y + 1);                }                if (showIndex < 0)                {                    xoff = Page.y - Math.Abs(xoff);                    yoff -= 1;                }            }        }        widget.Transform.gameObject.name = index.ToString();        widget.Transform.SetParent(transform);        widget.Transform.localScale = Vector3.one;        if (!isCustomizeHeight)        {            widget.Transform.anchoredPosition =                new Vector3(xoff * sizeData.x + posOff.x, -yoff * sizeData.y - addY - posOff.y);        }        else        {            float y = 0;            if (isUp)            {                y = -5000000;            }            else            {                y = 5000000;            }            IScorllListWidget yWidget = null;            for (int i = 0; i < showWidget.Count; i++)            {                IScorllListWidget scorllListWidget = showWidget[i];                int c = scorllListWidget.index - m_startIndex;                int lastY = c / Page.y;                if (isUp)                {                    if (lastY - yoff == 1)                    {                        float currY = scorllListWidget.Transform.localPosition.y;                        if (y < currY)                        {                            yWidget = scorllListWidget;                            y = currY;                        }                    }                }                else                {                    if (yoff - lastY == 1)                    {                        float currY = scorllListWidget.Transform.localPosition.y;                        if (y > currY)                        {                            yWidget = scorllListWidget;                            y = currY;                        }                    }                }            }            if (yWidget == null)            {                widget.Transform.localPosition = new Vector3(xoff * sizeData.x, -yoff * sizeData.y);            }            else            {                if (isUp)                {                    Vector3 pos = new Vector3(0, y + widget.GetSize().y + sizeData.y);                    widget.Transform.localPosition = pos;                }                else                {                    Vector3 pos = new Vector3(0, y - yWidget.GetSize().y - sizeData.y);                    widget.Transform.localPosition = pos;                }            }        }        if (ScrollRect.horizontal)        {            if (widget.Transform.localPosition.x > 0)            {                float x = widget.Transform.localPosition.x + sizeData.x;                if (x < myRectTransform.sizeDelta.x)                {                    x = myRectTransform.sizeDelta.x;                }                else                {                    myRectTransform.sizeDelta = new Vector2(x + overflowDistance,                        myRectTransform.sizeDelta.y);                }            }            // else            // {            //     m_startIndex--;            //     float x = Math.Abs(widget.Transform.localPosition.x);            //     myRectTransform.sizeDelta += new Vector2(x,            //      0);            //     MoveX(x);            // }        }        else        {            float y = 0;            if (isCustomizeHeight)            {                y = Math.Abs(widget.Transform.localPosition.y) + widget.GetSize().y;            }            else            {                y = Math.Abs(widget.Transform.localPosition.y) + sizeData.y;            }            if (widget.Transform.localPosition.y > 0)            {                if (isCustomizeHeight)                {                    float addY = widget.GetSize().y + sizeData.y;                    myRectTransform.sizeDelta += new Vector2(0, addY);                    if (index >= _maxSize && !hasAddedOffset)                    {                        myRectTransform.sizeDelta += new Vector2(0, bottom);                        hasAddedOffset = true;                    }                    MoveY(addY);                }                else                {                    myRectTransform.sizeDelta += new Vector2(0, sizeData.y);                    if (index >= _maxSize && !hasAddedOffset)                    {                        myRectTransform.sizeDelta += new Vector2(0, bottom);                        hasAddedOffset = true;                    }                    MoveY(sizeData.y);                }            }            else            {                if (y > myRectTransform.sizeDelta.y)                {                    myRectTransform.sizeDelta = new Vector2(myRectTransform.sizeDelta.x, y);                }                if (index >= _maxSize && !hasAddedOffset)                {                    myRectTransform.sizeDelta += new Vector2(0, bottom);                    hasAddedOffset = true;                }            }        }        widget.Transform.anchorMax = Vector2.up;        widget.Transform.anchorMin = Vector2.up;        widget.Transform.pivot = Vector2.up;        return widget;    }    protected void MoveY(float y)    {        ScrollRect.StopMovement();        addY += y;        ScrollRect.content.localPosition += new Vector3(0, y, 0);        for (int i = 0; i < showWidget.Count; i++)        {            IScorllListWidget scorllListWidget = showWidget[i];            Vector3 pos = scorllListWidget.Transform.localPosition;            scorllListWidget.Transform.localPosition = new Vector3(pos.x, pos.y - y, pos.z);        }    }    protected void MoveX(float x)    {        ScrollRect.StopMovement();        // addY += y;        myRectTransform.anchoredPosition -= new Vector2(x, 0);        // ScrollRect.content.localPosition += new Vector3(x, 0, 0);        for (int i = 0; i < showWidget.Count; i++)        {            IScorllListWidget scorllListWidget = showWidget[i];            Vector3 pos = scorllListWidget.Transform.localPosition;            scorllListWidget.Transform.localPosition = new Vector3(pos.x + x, pos.y, pos.z);        }    }    protected void HindWidget()    {        if (showWidget.Count < 2)        {            return;        }        for (int i = 0; i < showWidget.Count; i++)        {            bool isShow = false;            bool isHind = false;            GetIsShow(showWidget[i], ref isShow, ref isHind);            if (!isHind) //已经移除到了隐藏区域            {                HindIWidget(showWidget[i]);                i--;                if (showWidget.Count < 2)                {                    return;                }            }        }    }    public async void onValueChanged2(Vector2 pos)    {        onValueChanged(pos, false);    }    public async CTask onValueChanged(Vector2 pos, bool isInit)    {        if (_isBreak)        {            return;        }        if (!isInit && (_isBreak || _isStartDelay))        {            return;        }        // _vel = ScrollRect.velocity;        using (await CoroutineLockComponent.Instance.Wait("123"))        {            if (_isBreak)            {                return;            }            hasAddedOffset = false;            // ScrollRect.StopMovement();            HindWidget();            IScorllListWidget minWidget = null;            IScorllListWidget maxWdiget = null;            for (int i = 0; i < showWidget.Count; i++)            {                if (minWidget == null)                {                    minWidget = showWidget[i];                    maxWdiget = showWidget[i];                }                else                {                    if (minWidget.index > showWidget[i].index)                    {                        minWidget = showWidget[i];                    }                    if (maxWdiget.index < showWidget[i].index)                    {                        maxWdiget = showWidget[i];                    }                }            }            if (minWidget == null || maxWdiget == null)            {                //检查是否需要生成第一个                return;            }            bool isShow = false;            bool isHind = false;            GetIsShow(minWidget, ref isShow, ref isHind);            bool isShow3 = false;            bool isHind3 = false;            GetIsShow(maxWdiget, ref isShow3, ref isHind3);            if (isShow) //最小的在显示区域,需要生成下面的            {                IScorllListWidget wdiget = await Cread(minWidget.index - 1, true);                if (wdiget != null)                {                    bool isShow2 = true;                    bool isHind2 = false;                    while (isShow2 && wdiget != null)                    {                        if (_isBreak)                        {                            return;                        }                        GetIsShow(wdiget, ref isShow2, ref isHind2);                        if (isShow2)                        {                            if (_isStartDelay)                            {                                await TimerComponent.Instance.WaitAsync(delayTime);                            }                            if (_isBreak)                            {                                return;                            }                            wdiget = await Cread(wdiget.index - 1, true);                        }                    }                }            }            if (isShow3) //最小的在显示区域,需要生成下面的            {                IScorllListWidget wdiget = await Cread(maxWdiget.index + 1, false);                if (wdiget != null)                {                    bool isShow2 = true;                    bool isHind2 = false;                    while (isShow2 && wdiget != null)                    {                        if (_isBreak)                        {                            return;                        }                        GetIsShow(wdiget, ref isShow2, ref isHind2);                        if (isShow2)                        {                            if (_isStartDelay)                            {                                await TimerComponent.Instance.WaitAsync(delayTime);                            }                            if (_isBreak)                            {                                return;                            }                            wdiget = await Cread(wdiget.index + 1, false);                        }                    }                }            }            // ScrollRect.velocity = _vel;        }        // myRectTransform.sizeDelta=new Vector2(maxWdiget.index*)        // Debug.Log(pos);    }    public void GetIsShow(IScorllListWidget widget, ref bool isShow, ref bool isHind)    {        RectTransform root = ScrollRect.GetComponent<RectTransform>();        Vector2 posint = root.worldToLocalMatrix.MultiplyPoint3x4(widget.Transform.position);        Vector2 size = widget.GetSize();        isShow = false;        isHind = false;        Vector2 pos = Vector2.zero;        float minx = pos.x - (root.rect.size.x * root.pivot.x);        float miny = pos.y - (root.rect.size.y * root.pivot.y);        float maxx = pos.x + (root.rect.size.x * (1 - root.pivot.x));        float maxy = pos.y + (root.rect.size.y * (1 - root.pivot.y));        Vector2 rootPos = posint;        List<Vector2> widgetBox = GetBox(rootPos.x, rootPos.y - size.y, rootPos.x + size.x, rootPos.y);        for (int i = 0; i < widgetBox.Count; i++)        {            Vector2 p = widgetBox[i];            if (ScrollRect.vertical)            {                if (p.y > miny && p.y < maxy)                {                    isShow = true;                }                // if (p.y > miny - size.y - 100 &&                //     p.y < maxy + size.y + 100)                // {                //     isHind = true;                // }                //不依赖widget尺寸大小                if (p.y > miny - 200 &&                    p.y < maxy + 200)                {                    isHind = true;                }            }            else            {                if (p.x > minx && p.x < maxx)                {                    isShow = true;                }                if (p.x > minx - size.x - 100 && p.x < maxx + size.x + 100)                {                    isHind = true;                }            }        }    }    protected List<Vector2> GetBox(float minx, float miny, float maxx, float maxy)    {        List<Vector2> s = new List<Vector2>();        s.Add(new Vector2(minx, miny));        s.Add(new Vector2(minx, maxy));        s.Add(new Vector2(maxx, maxy));        s.Add(new Vector2(maxx, miny));        return s;    }    public async CTask<IScorllListWidget> GetWidget(int index)    {        IScorllListWidget listWidget =            await m_scrollListContent.GetIScorllListWidget(index, transform.GetComponent<RectTransform>());        if (listWidget == null)        {            return null;        }        listWidget.Transform.anchorMin = new Vector2(0, 1);        listWidget.Transform.anchorMax = new Vector2(0, 1);        listWidget.Transform.pivot = new Vector2(0, 1);        listWidget.Transform.localScale = Vector3.one;        listWidget.index = index;        return listWidget;    }    public async CTask<IScorllListWidget> GetIScorllListWidget(int index, RectTransform root)    {        if (hindWidget.Count > 0)        {            IScorllListWidget listWidget = hindWidget[0];            listWidget.Transform.gameObject.SetActive(true);            hindWidget.RemoveAt(0);            Debug.Log(index + "___" + listWidget.index);            listWidget.index = index;            return listWidget;        }        return null;    }    public void HindIWidget(IScorllListWidget widget)    {        showWidget.Remove(widget);        m_scrollListContent.HindIScorllListWidget(widget);    }    public void HindIScorllListWidget(IScorllListWidget widget)    {        widget.Transform.gameObject.SetActive(false);        Debug.Log("hindWidget___" + widget.index);        hindWidget.Add(widget);    }    /// <summary>    /// 计算目标索引对应的位置    /// </summary>    /// <param name="targetIndex">目标索引</param>    /// <returns>目标位置</returns>    private Vector2 CalculateTargetPosition(int targetIndex)    {        Vector2 targetPos = onePos; // 从初始位置开始计算        if (ScrollRect.horizontal)        {            // 水平滚动:计算 X 轴位置            int xOffset = (targetIndex - m_startIndex) / Page.x;            targetPos.x -= xOffset * sizeData.x + posOff.x;        }        else if (ScrollRect.vertical)        {            // 垂直滚动:计算 Y 轴位置            int yOffset = (targetIndex - m_startIndex) / Page.y;            if (!isCustomizeHeight)            {                targetPos.y = yOffset * sizeData.y + posOff.y;            }            else            {                // 如果是自定义高度,假设高度固定,实际需根据 GetSize() 动态调整                targetPos.y -= yOffset * sizeData.y + posOff.y;            }        }        return targetPos;    }    /// <summary>    /// 计算目标索引对应的 content sizeDelta    /// </summary>    /// <param name="targetIndex">目标索引</param>    /// <returns>目标 sizeDelta</returns>    private Vector2 CalculateTargetSizeDelta(int targetIndex)    {        Vector2 targetSizeDelta = myRectTransform.sizeDelta;        if (ScrollRect.horizontal)        {            // 水平滚动:根据目标索引计算总宽度            int totalColumns = (targetIndex + Page.y - 1) / Page.y; // 向上取整            targetSizeDelta.x = totalColumns * sizeData.x + overflowDistance;            targetSizeDelta.y = Page.y * sizeData.y; // 高度基于每列的控件数        }        else if (ScrollRect.vertical)        {            // 垂直滚动:根据目标索引计算总高度            int totalRows = (targetIndex + Page.y - 1) / Page.y; // 向上取整            if (!isCustomizeHeight)            {                targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;                targetSizeDelta.x = Page.y * sizeData.x; // 宽度基于每行的控件数            }            else            {                // 如果是自定义高度,简单假设高度固定,实际需根据已有控件动态计算                targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;                targetSizeDelta.x = Page.y * sizeData.x;            }        }        return targetSizeDelta;    }    private Vector2 CalculateBottomSizeDelta(int targetIndex)    {        Vector2 targetSizeDelta = myRectTransform.sizeDelta;        RectTransform root = ScrollRect.GetComponent<RectTransform>();        float viewportHeight;        if (ScrollRectSizedata.y == 0)        {            viewportHeight = root.rect.height;        }        else        {            viewportHeight = ScrollRectSizedata.y;        }        // float viewportHeight = root.rect.height;        if (ScrollRect.vertical)        {            // 计算可视行数            float itemHeight = isCustomizeHeight ? sizeData.y : sizeData.y; // 简化,实际需动态获取            int visibleRows = Mathf.CeilToInt(viewportHeight / itemHeight); // 向上取整            // 计算最低端索引            int bottomIndex = Mathf.Min(targetIndex + visibleRows * Page.y, _maxSize );            int totalRows = (bottomIndex + Page.y - 1) / Page.y; // 从 0 到 bottomIndex 的行数            if (!isCustomizeHeight)            {                targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;            }            else            {                // 动态高度简化处理                targetSizeDelta.y = totalRows * sizeData.y + overflowDistance;                // 实际应为:                // float totalHeight = 0f;                // for (int i = 0; i <= bottomIndex; i += Page.y)                //     totalHeight += (i < showWidget.Count) ? showWidget[i].GetSize().y : sizeData.y;                // targetSizeDelta.y = totalHeight + overflowDistance;            }            targetSizeDelta.x = Page.y * sizeData.x;            // Debug.Log(            //     $"最低端 sizeDelta - visibleRows: {visibleRows}, bottomIndex: {bottomIndex}, totalRows: {totalRows}, sizeDelta.y: {targetSizeDelta.y}");        }        else if (ScrollRect.horizontal)        {            int visibleColumns = Mathf.CeilToInt(root.rect.width / sizeData.x);            int rightIndex = Mathf.Min(targetIndex + visibleColumns * Page.x, _maxSize - 1);            int totalColumns = (rightIndex + Page.y - 1) / Page.y;            targetSizeDelta.x = totalColumns * sizeData.x + overflowDistance;            targetSizeDelta.y = Page.y * sizeData.y;        }        return targetSizeDelta;    }}
 |