Cocos Creator 组件ListView

摘要:
版本:2.3.4 Cocos没有List组件,所以您应该自己编写。从Cocos的示例项目中找到listView的演示,以修改新修改的listView。与原来相比,做了以下更改:1.删除了totalCount、spawnCount和bufferZone的计算,并根据实际情况自动计算适当的值。UI结构如下图所示:与cocosexample相比,ListView的所有UI都在一个节点上,便于制作预制件。

版本:2.3.4

cocos没有List组件,所以要自己写。

从cocos的example项目中找到listView的demo来改造

Cocos Creator 组件ListView第1张

新修改的ListView对比原来有以下改动:

1. 去掉了totalCount、spawnCount和bufferZone的计算,根据实际情况自动计算合适的值。

2. 增加了列表项数据的传入和刷新。例如排行榜做列表,可以传入排行榜数据[{rank:1,name:"啊",{rank:2,name:"啦"},...}]来显示。

3. 将ListViewCtrl和ScrollView两个Node,合成一个Node,做成prefab,并拖动到自定义控件区域,以备复用。

4. 去掉了addItem和removeItem,列表项由传入的data决定。

5. 增加了ListItem类来处理data数据的显示。

UI结构如下图:

对比cocos example的,ListView所有UI在一个节点上,方便做成预制件。

Cocos Creator 组件ListView第2张

ListView类:

import ListItem from "./ListItem";

const {ccclass, property} = cc._decorator;

/**
 * 列表
 * 根据cocos_example的listView改动而来
 * @author chenkai 2020.7.8
 */
@ccclass
export default class ListView extends cc.Component {

    /**列表选项 */
    @property(cc.Node)
    public item:cc.Node = null;

    /**列表选项类 */
    @property(cc.String)
    public itemClass:string = "";

    /**列表滚动容器 */
    @property(cc.ScrollView)
    public scrollView:cc.ScrollView = null;

    /**列表项之间间隔 */
    @property(cc.Integer)
    public spacing:number = 0;

    /**列表项实例数量 */
    private spawnCount:number = 0;
    /**距离scrollView中心点的距离,超过这个距离的item会被重置,一般设置为 scrollVIew.height/2 + item.heigt/2 + spaceing,因为这个距离item正好超出scrollView显示范围 */
    private bufferZone:number = 0;
    /**列表项总数 */
    public totalCount:number = 0;
    /**scrollView的内容容器 */
    private content:cc.Node = null;
    /**存放列表项实例的数组 */
    private items:Array<cc.Node> = [];
    /**刷新列表计时 */
    private updateTimer:number = 0;
    /**刷新列表间隔 */
    private updateInterval:number = 0;
    /**上一次content的Y值,用于和现在content的Y值比较,得出是向上还是向下滚动 */
    private lastContentPosY:number = 0;
    /**列表项数据 */
    private itemDataList:any = [];
    /**item的高度 */
    private itemHeight:number = 0;

    onLoad() {
        //初始化
        this.content = this.scrollView.content;
        this.items = [];
        this.updateTimer = 0;
        this.updateInterval = 0.1;
        this.lastContentPosY = 0;
        this.itemHeight = this.item.height;
        this.content.removeAllChildren();
        
        //计算创建的item实例数量,比当前scrollView容器能放下的item数量再加上2个
        this.spawnCount = Math.round(this.scrollView.node.height/( this.itemHeight + this.spacing)) + 2;
        //计算bufferZone
        this.bufferZone = this.scrollView.node.height/2 +  this.itemHeight/2 + this.spacing;
        //暂停滚动
        this.enabled = false;
        this.scrollView.enabled = false;
    }

    /**
     * 设置item的数据
     * @example
     *   setData([{id:1,msg:"a"},{id:2,msg:"b"}])
     * @param itemDataList item数据列表
     */
    public setData(itemDataList:any){
        //复制item数据,如果item数据源改变,则需要重新setData一次来显示新数据
        this.itemDataList = itemDataList.slice();
        this.totalCount = this.itemDataList.length;
        this.createItem();
        //运行滚动
        this.enabled = true;
        this.scrollView.enabled = true;
    }
    
    /**创建item实例 */
    private createItem () {
        this.content.height = this.totalCount * ( this.itemHeight + this.spacing) + this.spacing;
        this.clearAllItem();
        let len = this.totalCount < this.spawnCount?this.totalCount:this.spawnCount;
        for (let i = 0; i < len; i++) { // spawn items, we only need to do this once
            let item = cc.instantiate(this.item);
            this.content.addChild(item);
            item.setPosition(0, -item.height * (0.5 + i) - this.spacing * (i + 1));
            item.getComponent(this.itemClass).updateItem(i, this.itemDataList[i]);
            this.items.push(item);
        }
    }

    /**清理item实例 */
    private clearAllItem(){
        for(let i=0,len=this.items.length;i<len;i++){
            let item = this.items[i];
            item.destroy();
        }
        this.items.length = 0;
    }
    
    /**获取item在scrollView的局部坐标 */
    private getPositionInView(item) { 
        let worldPos = item.parent.convertToWorldSpaceAR(item.position);
        let viewPos = this.scrollView.node.convertToNodeSpaceAR(worldPos);
        return viewPos;
    }
 
    update(dt) {
        this.updateTimer += dt;
        if (this.updateTimer < this.updateInterval) return;
        this.updateTimer = 0;
        let items = this.items;
        let buffer = this.bufferZone;
        let isDown = this.scrollView.content.y < this.lastContentPosY; // scrolling direction
        let offset = ( this.itemHeight + this.spacing) * items.length;
        for (let i = 0; i < items.length; ++i) {
            let viewPos = this.getPositionInView(items[i]);
            if (isDown) {
                // if away from buffer zone and not reaching top of content
                if (viewPos.y < -buffer && items[i].y + offset < 0) {
                    //console.log("更新A前,items[i]:" + i +"viewPos.y:",viewPos.y,"buffer:" ,buffer,"items[i].y:", items[i].y,"offset:",offset,"this.content.height:",this.content.height);
                    items[i].y = items[i].y + offset;
                    let item = items[i].getComponent(this.itemClass);
                    let itemId = item.itemID - items.length; // update item id
                    //item.updateItem(itemId);
                    item.updateItem(itemId,this.itemDataList[itemId]);
                    //console.log("更新A后,tmpID:",item.tmplID,"itemId:" ,itemId,"viewPosY:", viewPos.y,"buffer:",buffer,"offset:",offset);
                }
            } else {
                // if away from buffer zone and not reaching bottom of content
                if (viewPos.y > buffer && items[i].y - offset > -this.content.height) {
                    //console.log("更新B前,items[i]:" + i +"viewPos.y:",viewPos.y,"buffer:" ,buffer,"items[i].y:", items[i].y,"offset:",offset,"this.content.height:",this.content.height);
                    items[i].y = items[i].y - offset;
                    let item = items[i].getComponent(this.itemClass);
                    let itemId = item.itemID + items.length;
                    //item.updateItem(itemId);
                    item.updateItem(itemId,this.itemDataList[itemId]);
                    //console.log("更新B后,tmpID:",item.tmplID,"itemId:" ,itemId,"viewPosY:", viewPos.y,"items[i].y:",items[i].y,"buffer:",buffer,"offset:",offset);
                }
            }
        }
        // update lastContentPosY
        this.lastContentPosY = this.scrollView.content.y;
    }
    
    /**
     * 滚动到指定位置
     * @param vec2 位置
     */
    public scrollToFixedPosition (vec2:cc.Vec2) {
        this.scrollView.scrollToOffset(vec2, 2);
    }

    /**销毁 */
    public onDestroy(){
        
    }
}

  

ListItem类:

const {ccclass, property} = cc._decorator;

/**
 * 列表项基类
 * @author chenkai 2020.7.8
 */
@ccclass
export default class ListItem extends cc.Component {
    /**当前项ID,0表示第一项 */
    public itemID:number = 0;
    /**数据 */
    public data:any;
    
    /**
     * 刷新
     * @param itemID 当前项ID
     * @param data   数据
     */
    public updateItem(itemID, data) {
        this.itemID = itemID;
        this.data = data;
        this.dataChanged();
    }

    /**数据改变 */
    protected dataChanged(){
        
    }

}

  

RankListItem类:

继承自ListItem,并重写了dataChanged方法,在Item上下滚动导致刷新时,重置文本。

import ListItem from "./ListView/ListItem";

const {ccclass, property} = cc._decorator;

@ccclass
export default class RankListItem extends ListItem {
    private rankLab:cc.Label;
    private nameLab:cc.Label;

    onLoad(){
        this.rankLab = cc.find("rankLab",this.node).getComponent(cc.Label);
        this.nameLab = cc.find("nameLab",this.node).getComponent(cc.Label);
    }

    protected dataChanged(){
        this.rankLab.string = "第" + this.data.rank;
        this.nameLab.string = this.data.name;
    }
}

  

HelloWorld代码中使用

import ListView from "./ListView/ListView";

const {ccclass, property} = cc._decorator;

@ccclass
export default class Helloworld extends cc.Component {
    //排行榜
    private rankListView:ListView;

    onLoad(){
        
    }

    start(){
        //获取排行榜ListView
        this.rankListView = cc.find("RankListView", this.node).getComponent(ListView);

        //设置排行榜数据
        let rankData = [{rank:1,name:"啊飞"},{rank:2,name:"肚肚"},{rank:3,name:"普洱"},
                        {rank:4,name:"电饭锅"},{rank:5,name:"松岛"},{rank:6,name:"撒嗄"}];

        this.rankListView.setData(rankData);

        //重新设置排行榜数据
        rankData = [{rank:1,name:"啊飞"},{rank:2,name:"肚肚"},{rank:3,name:"普洱"},
                    {rank:4,name:"电饭锅"},{rank:5,name:"松岛"},{rank:6,name:"撒嗄"},
                    {rank:7,name:"打手犯规"},{rank:8,name:"萨达"},{rank:9,name:"苟富贵"}];

        this.rankListView.setData(rankData);
        //销毁
        //this.rankListView.node.destroy();
    }
}

  

实际效果:

Cocos Creator 组件ListView第3张

Demo:

 https://files-cdn.cnblogs.com/files/gamedaybyday/ListViewDemo.7z

免责声明:文章转载自《Cocos Creator 组件ListView》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇window安装redis无法启动报错pdf.js 前端pdf预览 渲染文本图层支持复制 保证手机端清晰度 双指缩放 alloyfinger(手势)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【翻译】tus----一个可续传文件上传的开放协议

tus tus是一个可续穿文件上传协议,它以Http协议为载体,统一了一个文件断点续传的标准。 这篇文章翻译自https://tus.io/ 目前该协议版本信息如下: Version: 1.0.0 (SemVer)Date: 2016-03-25Authors:Felix Geisendörfer, Kevin van Zonneveld, Tim Kos...

iOS开发 Masonry的简单使用

首先,在正式使用Masonry之前,我们先来看看在xib中我们是如何使用AutoLayout     从图中我们可以看出,只要设置相应得局限,控制好父视图与子视图之间的关系就应该很ok的拖出你需要的需求。这里就不详细讲解具体拖拽的方法..... 然后,我们按着上图的属性来看看如何简单得使用Masonry 这里是Masonry给我们的属性  @pr...

ListView实现点击列排序

当我们用ListView显示数据时,有一种很人性化的设计便是单击ListView某一列,该列则以升序或降序排列。 自己定义一个类继承自IComparer接口 代码如下: classListViewSort:IComparer{privateintcol; privatebooldescK; publicListViewSort() { col...

什么,kafka能够从follower副本读数据了 —kafka新功能介绍

最近看了kafka2.4新版本的一些功能特性,不得不说,在kafka2.0以后,kafka自身就比较少推出一些新的feature了,基本都是一些修修补补的东西。倒是kafka connect和kafka stream相关的开发工作做的比较多。可能kafka的野心也不局限于要当一个中间件,而是要实现一个流处理系统的生态了。 这次要介绍的是我觉得比较有意思的两...

redis主从机制

1.redis replication的核心机制 (1).redis采用异步方式复制数据到slave节点,不过redis 2.8开始,slave node会周期性地确认自己每次复制的数据量 (2).一个master node是可以配置多个slave node的 (3).slave node也可以连接其他的slave node (4).slave node做...

widget 常用UI控件介绍

    一、单选框 单选框实例程序:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_pa...