首页 > 其他分享 >drawcall优化 - 无限滚动容器

drawcall优化 - 无限滚动容器

时间:2024-05-14 15:19:10浏览次数:22  
标签:node 容器 滚动 index drawcall private cellIndex let scroll

这是一个前端项目常见的一个问题dc优化。比如一个复杂的背包容器500个元素,如果使用粗暴的实例化500个元素进去,最终的dc无疑会是灾难的。在内存管理和性能角度上讲也是铺张浪费的。

看见效果如下 dc 1091

 

但实际上500个元素itemCell,在一个屏幕视界内能看到和交互的也就6~8个。从效能上考虑,只要能无缝衔接和复用少量的元素就能满足用户需求,根本不需要填鸭式的创建并使用500个itemCell。

基于这个优化方向,做一下简单的规则设计。

 

把屏幕分成3个区块 上下红色是过渡区,用来缓冲蓝色方块的itemCell, 中间绿色是可见有效区,实时一致的显示给到用户的itemcell

我们需要做的几件事是:

1.创建少量的itemCell置于content节点下,暂定18个

2.计算并控制好滑动区域(绿色区域)itemCell的间距大小,按照滑动行程,每2行(4个itemCell)的高度进行一次更新

3.更新的操作是重绘当前的容器子节点,并同时执行ScrollView.scrollToOffset,对齐子节点位置,让用户无感的衔接到重绘后的容器布局和位置,保证观感一致

4.校验并处理滑动上下边界问题。

 

以下是演示效果 dc优化到96 (实际占用只有40左右 ,每个itemCell 占用2)

 

 

废话不多说,上代码

import { _decorator, instantiate, Label, Node, ScrollView,UITransform, Vec2 } from 'cc';
import { UIbase } from '../UIbase';
import { itemCell } from '../../../module_recovery/itemCell';
const { ccclass, property } = _decorator;

@ccclass('UINotice7')
export class UINotice7 extends UIbase {

    @property({ type: Node, displayName: "滑动器" })
    private scrollNode: Node = null;

    @property({ type: Label, displayName: "滚动条真实y值" })
    private offsetLabel: Label = null;

    @property({ displayName: "元素数量" })
    private cellNum: number = 50;

    @property({ displayName: "无限滚动备选item数量" })
    private itemActualCount: number = 18;

    @property({ displayName: "每一页item数量" })
    private itemPageCount: number = 4;

    private scroll;
    
    //拖动窗口高度
    private viewHeigh = 0;
    private celllHeigh = 0;

    public static Instance: UINotice7 = null;

    //元素池
    // private cellPool: any = [];

    //元素下标
    private cellIndex = 0;

    //滚动条换算起点y
    // private transOffsetY = 0;

    //数据池
    private dataPool: any = [];

    //容器触底
    private isBottom = false;

    _onLoad(): void {
        UINotice7.Instance = this;
        this.node.active = false;

        // CMF.Instance.zIndex(this.node, UIZindex.UINotice2);
        this.scroll = this.scrollNode.getComponent(ScrollView)

        const cellNode = this.scroll.node.children[0].children[0].children[0];
        this.celllHeigh = cellNode.getComponent(UITransform).height;


        //生成数据池
        for (let index = 0; index < this.cellNum; index++) {
            this.dataPool.push(index)
        }
        console.log("初始化 this.dataPool  " + this.dataPool.length)

        // //动态创建阵列节点 全部
        // for (let index = 0; index < this.cellNum - 1; index++) {
        //     let insNode = instantiate(cellNode);
        //     insNode.setParent(this.scroll.node.children[0].children[0]);
        // }

        //动态创建 有限的阵列节点 ,n = itemActualCount
        for (let index = 0; index < this.itemActualCount - 1; index++) {
            let insNode = instantiate(cellNode);
            insNode.setParent(this.scroll.node.children[0].children[0]);
        }

        this.initItemCellData()

        this.scroll.node.on("scrolling", this.scrolling, this);
        this.scroll.node.on("scroll-began", this.scrollBegan, this);
        // this.scroll.node.on("scroll-to-top", () => { console.log("scroll-to-top") }, this);
        // this.scroll.node.on("scroll-to-bottom", () => { console.log("scroll-to-bottom") }, this);
        this.scroll.node.on("scroll-ended", this.scrollEnd, this);

        this.viewHeigh = this.scroll.node.children[0].getComponent(UITransform).height;
        console.log("窗口可以显示 n行元素: " + this.viewHeigh / this.celllHeigh)
    }


    //初始化item数据
    initItemCellData() {
        let contentNode = this.scrollNode.getChildByPath("view/content");
        console.log("更新cell 数据下标 " + this.cellIndex)
        for (let index = 0; index < contentNode.children.length; index++) {
            let element = contentNode.children[index];
            if (this.dataPool.length > this.cellIndex + index) {
                let dataId = this.dataPool[this.cellIndex + index]
                let itemC = element.getComponent(itemCell);
                itemC.init(dataId);
                element.active = true;
            }
            else {
                element.active = false;
                this.isBottom = true;
            }
        }
    }

    _onDestroy(): void {
        UINotice7.Instance = null;
    }

    scrolling(scrollview: ScrollView, eventType, customEventData) {
        // let tmpPercent = 0.5 //翻页触发百分比
        let offsetY = this.scrollNode.getComponent(ScrollView).getScrollOffset().y;
        let changeHeigh = this.celllHeigh * 2
        let Redundant = this.viewHeigh / 2//冗余的Y空间
        // console.log("scrolling " + "," + offsetY_percent.toFixed(2));

        if (!this.isBottom && offsetY >= changeHeigh + Redundant) {
            //刷新,数据下标 向下翻动一页
            this.cellIndex += this.itemPageCount;
            console.log("cellIndex + ", this.itemPageCount, this.cellIndex)
            this.refreshContent(- changeHeigh);
        }
        else if (this.cellIndex >= this.itemPageCount && offsetY <= (Redundant - changeHeigh)) {
            //刷新,数据下标 向下翻动一页
            this.cellIndex -= this.itemPageCount;
            this.refreshContent(changeHeigh);
            this.isBottom = false;
        }
    }

    scrollBegan(scrollview: ScrollView, eventType, customEventData) {
        // this.lastoffsetY = this.scrollNode.getComponent(ScrollView).getScrollOffset().y;
        // console.log("scrollBegan " + "," + this.lastoffsetY);
    }

    scrollEnd(scrollview: ScrollView, eventType, customEventData) {
        let offsetY = this.scrollNode.getComponent(ScrollView).getScrollOffset().y;
        console.log("scrollEnd " + "," + offsetY);
    }

    protected update(dt: number): void {
        this.offsetLabel.string = "Y坐标 " + this.scrollNode.getComponent(ScrollView).getScrollOffset().y.toFixed(2);

    }

    //动态刷新容器阵列
    private refreshContent(toOffsetY) {
        toOffsetY = toOffsetY - 20
        if (this.cellIndex > this.dataPool.length - this.itemPageCount) {
            this.cellIndex = this.dataPool.length - this.itemPageCount;
        }
        if (this.cellIndex < 0)
            this.cellIndex = 0;

        console.log("动态更新阵列 元素下标" + this.cellIndex, "翻页重定位 deltaY " + toOffsetY)
        //动态刷新容器阵列
        this.initItemCellData()

        //更新滚动条y
        let offsetY = this.scrollNode.getComponent(ScrollView).getScrollOffset().y;
        this.scrollNode.getComponent(ScrollView).scrollToOffset(new Vec2(0, offsetY + toOffsetY))
    }
}

 

标签:node,容器,滚动,index,drawcall,private,cellIndex,let,scroll
From: https://www.cnblogs.com/xiloweiEVE/p/18191329

相关文章

  • 42天【代码随想录算法训练营34期】第九章 动态规划part04(● 01背包问题,你该了解这些!
    **416.分割等和子集**classSolution:defcanPartition(self,nums:List[int])->bool:_sum=0dp=[0]*10001fornuminnums:_sum+=numif_sum%2==1:returnfalsetarget=......
  • 使用Docker容器运行jupyter
    jupyter运行ccdjupyter-c-kerneldockerrun-v$(pwd):/jupyter/jupyter_c_kernel/-v/home/jovyan/work:/home/jovyan/work-p8888:8888brendanrius/jupyter-c-kernel#注意给/home/jovyan/work权限MinimalCkernelforJupyterUsewithDocker(recommended)docker......
  • js 取滚动条 和视口大小
    functiongetScrollSize(){if(window.pageXOffset){return{x:window.pageXOffset,y:window.pageYOffset}}else{return{x:document.body.offsetLeft+document.documentElement.offsetLeft,......
  • Flex布局-容器项
    弹性盒子是一种用于按行或按列的一维布局方法.元素可以膨胀以填充额外的空间,也可以收缩以适应更小的空间.flex重点概览对于flex重要的理解点在于:主轴与交叉轴换行与缩写主轴对齐放市场交叉轴对齐方式基于了解完上面的内容,我们能用flex布局实现如下几种......
  • docker快速部署 influxdb+telegraf+grafana 推送主机及docker容器监控数据 并展示图
    简述1、InfluxDBInfluxDB是用Go语言编写的一个开源分布式时序、事件和指标数据库,无需外部依赖。 2、TelegrafTelegraf是一个插件驱动的服务器代理,用于收集和报告指标,并且是TICKStack的第一部分。Telegraf插件可以直接从它运行的系统中获取各种指标,从第三方API中提取指标,甚......
  • 离散数学_集合运算_容器实现
    define_CRT_SECURE_NO_WARNINGS1/*1.求任意两个集合的交集、并集、差集2.求任意一个集合的幂集3.求任意一个集合的m元子集*/includeincludeincludeincludeusingnamespacestd;//检验一个元素是否已经存在于集合中boolexisted(vectors,chara){boolexist=fa......
  • set 容器详解 附大根堆题解
    声明本文中题解部分内容大部分转载自@sonnety的这篇博客中,本文为为方便复习而写的结论类文章,读者可自行跳转至原文处阅读。PART1set什么是set——来源cppreference简言之,它就是一种存进去就可以自动按升序排列的特殊容器,通常的set还具有自动去重的功能。定义方......
  • Docker容器定时备份MySQL数据库
    1.系统环境mysql8、centos7.92.创建mysql_backup.sh文件#!/bin/bash#获取容器idcontainer_id=`/usr/bin/dockerps-aqf"name=mysql-8.0"`echo"mysql的镜像IDis$container_id"#登录用户名mysql_user="xxx"#登录密码(注意如果密码包含特殊符号前面要用'......
  • Docker容器与守护进程运维 --项目四
    一、Docker容器配置进阶 1、容器的自动重启Docker提供重启策略控制容器退出时或Docker重启时是否自动启动该容器。容器默认不支持自动重启,要使用 --restart 选项指定重启策略。作用:容器自动重启;重启策略能够确保关联的多个容器按照正确的顺序启动。容器重启选项值:重启......
  • 在Linux中,什么是滚动更新和静态更新?
    在Linux系统中,滚动更新(RollingUpdate)和静态更新(StaticUpdate)是两种不同的系统更新和维护策略,它们各自有不同的特点和应用场景。1.滚动更新(RollingUpdate)定义:滚动更新是一种连续的更新策略,用于在最小化停机时间的情况下更新系统或软件服务。这种更新通常用于服务和应用程序......