cocos creator长列表优化之超出显示区域的隐藏,优化scrollView 列表,Grid列表,通过显示隐藏的方式优化DrawCall,可通用

本文介绍了Cocos Creator 3.3.2中优化长列表的方法,避免过多渲染导致的drawCall增加和卡顿。通过隐藏超出显示区域的列表项,而非仅实例化固定数量,同时强调不能使用layout以免排序混乱,需要手动设置位置。内容包括纵向滑动列表和Grid滑动的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

版本 cocos creator3.3.2

这里我把mask打开,看看效果

长列表优化,隐藏区域外的

20220411_161150

长列表优化一直是游戏优化的重点内容,特别是在真机上。排行榜,背包等等的数据,渲染太多,导致drawCall增加,卡顿

之前我的博客中有另一个方式实现长列表优化,就是只实例化固定数量,然后这个固定数量在滑动中不断的切换显示数据

CocosCreator无尽循环列表,长列表优化drawcall,scrollview列表优化_似水流年wxk的博客-优快云博客

现在介绍一个新的可以通用的方法,就是依然都实例化,只是超过显示区域的隐藏掉,但是content不能加layout来布局,因为加layout,隐藏子节点后,就排序乱了,一定要代码自己设置位置

1.首先说一下纵向滑动列表(非Grid滑动)

(1)content节点的位置,移到显示区域的上面,第一个item的位置

(2) item的根节点要有高度,和item背景一样的高度

看一下我的scrollView 的配置 这是我的content

其他的配置都是默认就行,滑动区域主要是在深色区域 上代码 


import { _decorator, Component, Node, ScrollView, UITransform, Vec3, instantiate, Size } from 'cc';
import UIBase from '../../UIFrame/UIBase';
import { UIPackLinkRecordItem } from './UIPackLinkRecordItem';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = UIPackLinkRecord
 * DateTime = Mon Apr 11 2022 14:55:36 GMT+0800 (中国标准时间)
 * Author = fywxk
 * FileBasename = UIPackLinkRecord.ts
 * FileBasenameNoExtension = UIPackLinkRecord
 * URL = db://assets/scripts/UI/UIknapsack/UIPackLinkRecord.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
 *
 */
 
@ccclass('UIPackLinkRecord')
export class UIPackLinkRecord extends Component{
    @property(Node)
    private viewContent: Node = null;// 滑动父节点

    @property(ScrollView)
    private scrollView: ScrollView = null;// 

    @property(Node)
    private itemNode: Node = null;// item 节点

     
    needJudge = false;// 是否需要判断滑动区域隐藏

    itemDis = 6;// 间距

    paddingUp = 10;// 开始的偏移,上面的偏移10个像素

    itemCount = 60;

    start () {
       this.refreshUI();
    }
   
    requestList()
    {
    }
    // 刷新列表界面
    refreshUI()
    {
        // 销毁之前的数据,不判断隐藏
        this.needJudge = false;
        this.viewContent.removeAllChildren();
        
        let itemHeight = this.itemNode.getComponent(UITransform).height;// item高度
        // 实例化item 60个
        for(var i=0;i<this.itemCount ;i++)
        {
            // 计算位置  第一个是-item高度的一半,后面就是(item高度+间距)*i
           let pos = new Vec3(0,-itemHeight/2-this.paddingUp+((-itemHeight-this.itemDis) * i),0);
            // 获取item脚本赋值
           let a:Node = instantiate(this.itemNode);
           a.active = true;
           a.getComponent(UIPackLinkRecordItem).setValue("");
           a.parent = this.viewContent;
           a.setPosition(pos);
        }
          // 设置content内容的高度,就是内容的总高度
        let size = this.viewContent.getComponent(UITransform).contentSize;
        this.viewContent.getComponent(UITransform).setContentSize(new Size(size.width,(itemHeight+this.itemDis)*this.itemCount +this.paddingUp));
        this.needJudge = true;// 开始计算隐藏
    }
    update()
    {
        // 判断滑动超出区域,就隐藏,降低drawcall
        if(this.needJudge)
        {
            let itemHeight = this.itemNode.getComponent(UITransform).height+this.itemDis;// item+间距  
            let height = this.viewContent.getComponent(UITransform).height;// 总高度
            let viewHeight = this.scrollView.getComponent(UITransform).height;// 视口高度
            let offsetUp = this.scrollView.getScrollOffset().y;// 相对于左上的滑动偏移
            if(height-viewHeight<=0) return;// 不需要滑动,小于显示区域
             // 遍历子节点
            this.viewContent.children.forEach(item=>{
                if(item.position.y+offsetUp>itemHeight) // 不滑动的时候偏移是0
                {// 判断上面隐藏  大于一个item高度的隐藏
                    item.active = false;
                }
                else if(item.position.y+offsetUp+viewHeight<-itemHeight)
                {// 判断下面隐藏  y+偏移+视口高度  小于-item高度
                    item.active = false;
                }
                else item.active = true;// 其他的都显示
            })
        }
    }
}

2.首先说一下纵向滑动Grid滑动,和上面的代码大同小异,就是设置位置的问题

(1)content节点的位置,移到显示区域的上面,第一个item的位置

(2) item的根节点要有高度,和item背景一样的高度

上代码


import { _decorator, Component, Node, v2, Vec3, Label, Color, math, v3, instantiate, UITransform, Size, ScrollView, view } from 'cc';
import { RowBetween } from '../../../../contractReactProject/src/components/Row';
import { UIPackLinkItem } from './UIPackLinkItem';
import { UIPackLinkRecord } from './UIPackLinkRecord';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = UIPackUpLink
 * DateTime = Sat Apr 09 2022 15:53:05 GMT+0800 (中国标准时间)
 * Author = fywxk
 * FileBasename = UIPackUpLink.ts
 * FileBasenameNoExtension = UIPackUpLink
 * URL = db://assets/scripts/UI/UIknapsack/UIPackUpLink.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
 *
 */
 
@ccclass('UIPackUpLink')
export class UIPackUpLink extends Component{
    @property(Node)
    private closeButton: Node = null;

    @property(Node)
    private recordButton: Node = null;

    @property(Node)
    private pageBtnParent: Node = null;// 页签父节点

    @property(Node)
    private goodsPageBtnParent: Node = null;// 物品页签父节点

    @property(Node)
    private viewContent: Node = null;// 滑动父节点

    @property(ScrollView)
    private scrollView: ScrollView = null;// 

    @property(Node)
    private itemNode: Node = null;// item
    
    needJudge = false;// 是否需要判断滑动区域隐藏

    lineNum = 6;// 每行数量

itemCount = 60;// 总数

    itemDis = 17;// 上下左右间距

    pageType:"";// 页面类型 up/down

    start () {   this.refreshUI();
      
    }
   
    // 刷新列表界面
    refreshUI()
    {
        this.needJudge = false;
        this.viewContent.removeAllChildren();
        
        let itemHeight = this.itemNode.getComponent(UITransform).height;
        let itemWidth = this.itemNode.getComponent(UITransform).width;
        let posX = -this.viewContent.getComponent(UITransform).width/2+itemWidth/2+1;
        // 实例化item 60个
        for(var i=0;i<this.itemCount;i++)
        {
            // 这里计算一下位置,x:每行有6个  0或者6的倍数除6求余,得到是0就是第一个,其他的都往后排
// y:总数 /6 是行数 乘以item的高度加间距
           let pos = new Vec3(i%this.lineNum==0?posX: posX+(itemWidth+this.itemDis)*(i%this.lineNum),-itemHeight/2+((-itemHeight-this.itemDis) * Math.floor(i/this.lineNum)),0);
           let a:Node = instantiate(this.itemNode);
           a.active = true;
           a.getComponent(UIPackLinkItem).setValue(this.pageType);
           a.parent = this.viewContent;
           a.setPosition(pos);
        }
        // 设置高度
        let size = this.viewContent.getComponent(UITransform).contentSize;
        this.viewContent.getComponent(UITransform).setContentSize(new Size(size.width,(itemHeight+this.itemDis)*Math.ceil(this.itemCount /this.lineNum)));
        this.needJudge = true;
    }
    update()
    {
        // 判断滑动超出区域,就隐藏,降低drawcall
        if(this.needJudge)
        {
            let itemHeight = this.itemNode.getComponent(UITransform).height+this.itemDis;
            let height = this.viewContent.getComponent(UITransform).height;// 总高度
            let viewHeight = this.scrollView.getComponent(UITransform).height;// 视口高度
            let offsetUp = this.scrollView.getScrollOffset().y;// 相对于左上的滑动偏移
            if(height-viewHeight<=0) return;// 不需要滑动
            this.viewContent.children.forEach(item=>{
                if(item.position.y+offsetUp>itemHeight)
                {// 判断上面隐藏
                    item.active = false;
                }
                else if(item.position.y+offsetUp+viewHeight<-itemHeight)
                {// 判断下面隐藏
                    item.active = false;
                }
                else item.active = true;
            })
        }
    }
}

注意:这套代码,只要设置好间距,总数,开始的偏移(可没有),再加上item预制体的高度,content的位置,几乎可以通用在任何长列表

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值