unity 实现数据驱动的无限滚动视图

git仓库:keiqkeqi321/LoopScrollView

1.实现目的

游戏功能中会遇到几百上千个条目放在一个页面上的需求,这无疑是不现实的.解决的方法是使用 UGUI 的ScrollView组件,将其 Content 加上 GridLayoutGroup网格排版组件和ContentSizeFilter,根据内容自动调整尺寸组件.再数据列表项全部生成出来加到Content里面.这就是基础的滚动视图的做法.

这样虽然能实现一些少量数据的需求,但是显示海量数据对内存也是极大的考验.

 2.实现思路

1.只显示可视区域

既然可展示的数据只有ScrollView 的Viewport那么大,那么就可以只生成并显示 Viewport覆盖的所有的列表项就可以.列表数据注入的时候根据数据规模调整 content的 size,使其尺寸可以容纳所有的列表项,并计算可视范围可以容纳多少个列表项,生成可视的所有列表项多一行的列表项. 

totalRow = Mathf.CeilToInt(count / (float)constraintCount);
rectTrans.sizeDelta = new UnityEngine.Vector2(rectTrans.sizeDelta.x, totalRow *             
         cellSize.y + (totalRow - 1) * spacing.y+padding.top);
viewRow = Mathf.CeilToInt(frame.y / (int)(cellSize.y + spacing.y) + 1);
int viewCount=viewRow * constraintCount;
int  needSpawn=viewCount;
for (int i = 0; i < needSpawn; i++)
{
    AddItem(Spawn().gameObject);
}

2.处理视图滚动 

ScrollView的视图滚动的时候,会触发一个事件,订阅这个事件来处理向上向下滚动,计算这一帧的滚动跨度,如果大于每行个数就调用 JumpTo 来直接跳跃到需要显示的内容.上滑时检查最下一行列表项的下边界是否高于视图下边界,如果高于则将最上一行列表项回收,在最后一行生成.下滑检测也是如此.

Vector2 last = new Vector2();
void OnSlide(Vector2 vector)
        {

            float span = Mathf.Abs(vector.y - last.y);
            if (loopItemDatas.Count * span > constraintCount)
            {
                loopContent.JumpTo(vector.y);
            }
            else
            {
                if (vector.y < last.y)
                {
                    UpSlideCheck(vector);
                }
                else if (vector.y > last.y)
                {
                    DownSlideCheck(vector);
                }
            }
            last = vector;
        }       
void DownSlideCheck(Vector2 vector)
        {
            float top = loopContent.TopPosi;
            float max = viewPort.position.y;
            if (top < max)
            {
                //
                loopContent.DownSlide();
            }

        }
        void UpSlideCheck(Vector2 vector)
        {
            float bottom = loopContent.BottomPosi;
            float min = viewPort.position.y - viewSize.y;
            if (bottom > min)
            {
                //
                loopContent.UpSlide();
            }
        }

3.数据驱动

显示层的东西都是从原列表项中读取出来的,并且没有对原数据列表隔壁那个改.所以增删改等操作只需要改动原列表数据,然后调用刷新,视图就会自动刷新.

3.如何使用

1.准备工作

创建用于承载显示数据的数据类,定义需要展示的所有数据,以及点击回调

public class LoopItemDataExample : LoopItemData
    {
        public Action clickAction;
        public String showText;
    }

创建用于显示列表项的 UI 组件类

public class LoopItemExample : LoopItem
    {
        public Text showText;
        LoopItemDataExample data1;
        public Button button;
        void Start(){
            button.onClick.AddListener(()=>{
                data1?.clickAction?.Invoke();
            });
        }
        protected override void UpdateInfor(LoopItemData data)
        {
            if(data.isEmpty){
                button.image.color=Color.gray;
                showText.text = null;
                data1 =null;
                return;
            }
            button.image.color=Color.white;
            data1 = data as LoopItemDataExample;
            showText.text = data1.showText;
        }
    }

将 LoopItemExample挂到场景需要复用显示的 itemTemplate 上.

将LoopContent挂到 Content 上

将LoopScrollView挂到ScrollView上并挂载依赖,其中Constraint用于限制每行个数

 2.功能调用

初始化显示数据,并注入

public LoopScrollView loopScrollView;
        public int count = 10000;
        List<LoopItemData> datas ;
        void Start()
        {
            //初始化数据
            datas = new List<LoopItemData>(count);
            for (int i = 0; i < count; i++)
            {
                var j = i;
                datas.Add(new LoopItemDataExample()
                {
                    id = j,
                    clickAction = () =>
                    {
                        Debug.Log("you click order " + j + " item");
                    },
                    showText = j.ToString(),
                });
            }
            //注入驱动数据
            loopScrollView.InitInfor(datas);

        }

数据驱动功能使用,就是更改原数据列表,再调用刷新就好了

if (Input.GetKeyDown(KeyCode.A))
            {
                int id=datas.Last().id+1;
                //加数据
                datas.Add(new LoopItemDataExample()
                {
                    id = datas.Last().id+1,
                    clickAction = () =>
                    {
                        Debug.Log("you click order " + id + " item");
                    },
                    showText = id.ToString(),
                });
                loopScrollView.Refresh();
            }
            if (Input.GetKeyDown(KeyCode.D))
            {
                //删除数据
                datas.RemoveAt(datas.Count - 1);
                loopScrollView.Refresh();
            }
            if (Input.GetKeyDown(KeyCode.S))
            {
                //改数据
                (datas[0] as LoopItemDataExample).showText = "i am after";
                loopScrollView.Refresh();
            }
        }

  • 45
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值