UGUI无限滚动

这个主要是用了Grid Layout Group组件
核心代码有三部分,第一部分是判断当前要展示的下标,第二部分是位置的更新,第三部分是数据的更新.
先说第一部分得到要展示的下标,也就是说得到要展示第几个到第几个数据

        public void GetInViewIndexRange(Rect rect, out int from, out int to)
        {
            Vector2 lt = new Vector2(rect.xMin - PaddingLeft, rect.yMin - PaddingTop);
            Vector2 rb = new Vector2(rect.xMax - PaddingLeft, rect.yMax - PaddingTop);

            float w = CellSizeX + SpacingX;
            float h = CellSizeY + SpacingY;

            int col = (int) (lt.x / w);
            int row = (int) (lt.y / h);
            from = GetIndexOfRowCol(row, col);
            
            col = (int) (rb.x / w);
            row = (int) (rb.y / h);
            to = GetIndexOfRowCol(row, col);
        }

        private int GetIndexOfRowCol(int row, int col)
        {
            if (Constraint == GridLayoutGroup.Constraint.FixedColumnCount)
            {
                if (col >= ConstraintCount)
                {
                    col = ConstraintCount - 1;
                }
                return row * ConstraintCount + col;
            }
            
            if (Constraint == GridLayoutGroup.Constraint.FixedRowCount)
            {
                if (row >= ConstraintCount)
                {
                    row = ConstraintCount - 1;
                }
                return col * ConstraintCount + row;
            }

            return 0;
        }

这部分代码还蛮好理解的,只要只要这些参数是干嘛的就好了,首先第一个参数是传入了一个Rect也就是一个矩形,这个矩形怎么得到的下面再说,然后lt是用矩形的最小x和最小y减去左上的偏移量,这两个偏移量是Grid Layout Group组件的,为了帮助大家理解我在下面放了组件的图,方法中用到的参数请一一对号入座.
https://docs.unity3d.com/Manual/script-GridLayoutGroup.html组件的官方文档,参数是干嘛用的详情就看文档吧,我就不一一说明


然后rb是用矩形的最大x和最大y减去左上的偏移量,为什么减去左上是因为咱们这个锚点要设置为左上角,中心点(Pivot)设置成01.
w和h就是物体的宽和高,用x/长,y/高,这样来计算出当前的行列.
再看一下GetIndexOfRowCol方法,首先判断下是固定行还是固定列,咱们就拿固定列来说,用之前算的col也就是当前列数与自己设定的固定列数比较,如果大于等于的话就设置为固定列数-1(这是因为下标是从0开始,我是这么理解的),最后再用当前行数*固定列数+计算过后的当前列数,就是当前的下标(第一次用是计算起始下标,第二次是计算结尾下标,用于后面的数据更新和判断是否要增加或减少Item).
这样第一部分就完成了.对了讲一下Rect是怎么获得的

            var rt = _content.parent.GetComponent<RectTransform>();
            var rect = rt.rect;
            _viewHeight = rect.height;
            _viewWidth = rect.width;           
            var pos = content.anchoredPosition;
            _viewRect = new Rect(-pos.x, pos.y, _viewWidth, _viewHeight);

content是Scroll View组建的Content,取得是它的锚点位置,加上它父物体的大小(遮罩的大小)

    public void OnUpdateView     
    {
            var pos = _content.anchoredPosition;
            _viewRect = new Rect(-pos.x, pos.y, _viewWidth, _viewHeight);
            UpdateView();
    }

然后在滑动的监听事件中实时更新锚点位置,通过新的锚点位置去更新视图

第二个重点是位置的更新,之前说过这个是仿照着Grid Layout Group组件写的,位置判断也会用到组件的数据

        private void DoLayoutForFixedColumnCount(List<RectTransform> rts, int fromIndex)
        {
            for (int i = 0; i < rts.Count; ++i)
            {
                int index = fromIndex + i;
                rts[i].anchoredPosition = GetPositionOfIndexForFixedColumn(index);
            }
        }

        private void DoLayoutForFixedRowCount(List<RectTransform> rts, int fromIndex)
        {
            for (int i = 0; i < rts.Count; ++i)
            {
                int index = fromIndex + i;
                rts[i].anchoredPosition = GetPositionOfIndexForFixedRow(index);
            }
        }

        private Vector2 GetPositionOfIndexForFixedColumn(int index)
        {
            int col = index % ConstraintCount;
            int row = index / ConstraintCount;

            float lx = PaddingLeft + col * (CellSizeX + SpacingX);
            float ly = PaddingTop + row * (CellSizeY + SpacingY);
            
            return new Vector2(lx, -ly);
        }

        private Vector2 GetPositionOfIndexForFixedRow(int index)
        {
            int row = index % ConstraintCount;
            int col = index / ConstraintCount;

            float lx = PaddingLeft + col * (CellSizeX + SpacingX);
            float ly = PaddingTop + row * (CellSizeY + SpacingY);
            
            return new Vector2(lx, -ly);
        }

也是分为横竖,还是拿固定列当例子rts列表是当前实例的Item,fromIndex是当前开始的下标.用index%固定列数,能求出是在第几列,用index/固定列数求出当前是在第几行,再用求出的行列去乘上Item的宽高就能得到当前的位置了.
Note:Item的锚点和中心点也是在左上
附加一个计算Content大小的方法

        public void SetItemCount(int count)
        {
            if (Constraint == GridLayoutGroup.Constraint.FixedColumnCount)
            {
                int columns = ConstraintCount;
                int rows = (count + ConstraintCount - 1) / ConstraintCount;
                Width = PaddingLeft + CellSizeX * columns + SpacingX * (columns - 1) + PaddingRight;
                Height = PaddingTop + CellSizeY * rows + SpacingY * (rows - 1) + PaddingBottom;
            }
            else if (Constraint == GridLayoutGroup.Constraint.FixedRowCount)
            {
                int rows = ConstraintCount;
                int columns = (count + ConstraintCount - 1) / ConstraintCount;
                Width = PaddingLeft + CellSizeX * columns + SpacingX * (columns - 1) + PaddingRight;
                Height = PaddingTop + CellSizeY * rows + SpacingY * (rows - 1) + PaddingBottom;
            }
        }

参数count是要展示的数据的个数

最后就是数据的更新了

        private void UpdateItemDatas()
        {
            var index = _fromIndex;
            foreach (var item in _items)
            {
                if (_dataDirty || item.GetIndex() != index)
                {
                    item.SetIndex(index);
                    item.SetData(_datas[index]);
                }
                ++index;
            }
            _dataDirty = false;
        }

从第一步计算的开始下标开始给Item列表赋值就ok了.

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值