cocos creator TableView

cc.Class({
    extends: cc.Component,
    properties: {
        // item:[cc.Prefab],
        // itemData:[],//item数据
        // scrollView:cc.ScrollView,
        // itemInterval:0, //间距
        // firstItemData:{},
        // lastItemData:{},
        // itemArr:[],
        // itemNode:[],
    },
    //得到此脚本的节点下总控制脚本,用来传递给它的所有成员item;
    setTarget(target) {
        this.target = target;
    },
    //itemData是item数据,itemPosMap是滚动条滚动时要用到的item位置数据.
    init(itemData, scrollView, item, itemInterval, scrollViewCanFix, isSkipInit) {
        //前三项不能为空
        if (!itemData||!scrollView||!item) {  
            return false;  
        }  
        
        this.itemData = itemData; //item数据
        this.scrollView = scrollView;
        if(item.constructor!==Array){
            let arr=[];
            arr.push(item);
            this.item=arr;
        }else{
            this.item = item;
        }
        this.itemInterval = itemInterval || 0; //间距
        this.scrollViewCanFix = scrollViewCanFix || true; //是否自动修正
        //初始化各类属性
        this.content = this.scrollView.content;
        this.layerHeight = this.scrollView.node.height;
        this.updateTimer = 0;
        this.updateInterval = 5;
        this.firstItemIndex = 0;
        this.lastItemIndex = 0;
        this.firstItemData = {};
        this.lastItemData = {};
        this.itemArr = [];
        this.itemNode = [];
        this.itemPosMap = new Map();
        this.initItemData = true;
        this.count = 0;
        this.itemNodeHeight=[];
        this.scrollView.node.on('scrolling', this.callback,this);
        if (isSkipInit||itemData.length<1) {
            return;
        }
        this.initItem();
    },
    //能取到指定index的位置信息,用来设置预制体的位置
    getItemPos(index) {
        if(this.itemData.length<1){
            return 0;
        }
        for (let i = index; i < this.itemData.length; i++) {
            let obj = {}
            let y;
            if (i === 0) {
                obj.startPos = 0;
            } else {
                obj.startPos = this.itemPosMap.get(i - 1).endPos;
            }
            let j = this.itemData[i].pfbType||0;
            //若不存在预制体的高度,获取得之.
            if(this.itemNodeHeight[j]){
                obj.endPos = obj.startPos + this.itemNodeHeight[j] + this.itemInterval;
            }else{
                let y;
                if(i-1>=0){
                     y=this.itemPosMap.get(i- 1).endPos;
                }else{
                    y=0;
                }
                this.addItemNode(i,-y);
                obj.endPos = obj.startPos + this.itemNodeHeight[j] + this.itemInterval;
            }
            this.itemPosMap.set(i, obj);
        }
        this.updateContentHeigh(this.itemPosMap.get(this.itemData.length - 1).endPos);
    },
    //第一次加载的时候实例化预制体
    initItem() {
        //实例化所有用到的item;j控制实例化item的数目,暂定超出两个
        let j = 0;

        for (let i = 0; i < this.itemData.length; i++) {
            if (this.content.height > this.layerHeight) {
                    break;
            }
            let y;
            if (i === 0) {
                y = 0;
            } else {
                y = this.itemArr[i - 1].y - this.itemArr[i - 1].height - this.itemInterval;
            }
            this.addItemNode(i, y);
            this.updateContentHeigh(this.itemArr[i].height - y);
        }

    },
    //滚动时,当缓存数组this.itemArr没有相关预制体时,生成一个
    addItemNode(i, y) {
        let pfbType = this.itemData[i].pfbType||0;
        let item = this.getItemNode(pfbType);
        item.parent = this.content;
        item.pfbType = pfbType;
        item.index = i;
        if (i === 0) {
            item.y = 0;
        } else {
            item.y = y;
        }
        item.x = 0;
        //对item赋值
        item.getComponent(cc.Component).init(this.itemData[i], this);
        this.itemArr.push(item);
    },
    getItemNode(pfbType){
        let item=cc.instantiate(this.item[pfbType]);
        this.itemNodeHeight[pfbType]=item.height;
        return item;
    },
    updateContentHeigh(num) {
        this.content.height = num > this.layerHeight ? num : this.layerHeight;
        //cc.log('滚动条高度:', this.content.height);
    },
    //触摸滚动条的函数回调
    callback(event, eventType) {
        this.updateTimer += 1;
        if (this.updateTimer < this.updateInterval) return; // we don't need to do the math every frame
        this.updateTimer = 0;
        //cc.log(event && event.type || eventType)
        if (this.content&&this.content.height > this.layerHeight) {

            let firstItemPos = this.scrollView.getScrollOffset().y;
            let lastItemPos = firstItemPos + this.layerHeight;
            if (firstItemPos < 0) return;
            //只执行一次的额外初始化.
            if (this.initItemData) {
                this.getItemPos(0);
                this.initItemData = false;
                this.updateFirstItemIndex(firstItemPos);
                this.itemCanMoveDown = true;
                this.updateLastItemIndex(lastItemPos);
                this.itemCanMoveDown = false;
            }

            //超出边界直接返回.
            //滚动条向上滑动可能会触发的函数
            if (firstItemPos > this.firstItemData.endPos) {
                if (this.lastItemIndex + 1 < this.itemData.length) {
                    this.updateFirstItemIndex(firstItemPos);
                }
                this.count++;
            }
            if (lastItemPos > this.lastItemData.endPos) {
                if (this.lastItemIndex + 1 < this.itemData.length) {
                    this.itemCanMoveDown = true;
                    this.updateLastItemIndex(lastItemPos);
                    this.itemCanMoveDown = false;
                }
            }
            //滚动条向下滑动可能会触发的函数
            if (lastItemPos < this.lastItemData.startPos) {
                this.updateLastItemIndex(lastItemPos);
                this.count--;
            }
            if (firstItemPos < this.firstItemData.startPos) {
                this.itemCanMoveUp = true;
                this.updateFirstItemIndex(firstItemPos);
                this.itemCanMoveUp = false;
            }

        }

    },
    //顶部的预制体index改变的时候进行预制体移动操作.
    updateFirstItemIndex() {
        let num = this.firstItemIndex;
        if (this.itemCanMoveUp && num > this.getItemIndex()[0] && num > 0) {
            this.itemMoveUp(this.firstItemIndex - 1);
        }
    },
    //底部的预制体index改变的时候进行预制体移动操作.
    updateLastItemIndex() {
        let num = this.lastItemIndex;
        if (this.itemCanMoveDown && num < this.getItemIndex()[1] && num + 1 < this.itemData.length) {
            this.itemMoveDown(this.lastItemIndex + 1);
        }
    },
 
    
    //得到滚动条此时状态下应有的itemNode元素,包括滚动条上方一个,滚动条下方一个.
    getItemIndex() {
        let firstItemPos = this.scrollView.getScrollOffset().y;
        let lastItemPos = firstItemPos + this.layerHeight;
        let arr = [];
        for (let [key, value] of this.itemPosMap.entries()) {
            //判断状态的位置关系是[);
            let status1 = value.startPos <= firstItemPos && value.endPos > firstItemPos;
            // let status2 = value.startPos >= firstItemPos && value.endPos < lastItemPos;
            let status3 = value.startPos <= lastItemPos && value.endPos > lastItemPos;
            if (status1) {
                this.firstItemData.startPos = value.startPos;
                this.firstItemData.endPos = value.endPos;
                this.firstItemIndex = key;
                arr.push(key);
            }
            if (status3) {
                this.lastItemData.startPos = value.startPos;
                this.lastItemData.endPos = value.endPos;
                this.lastItemIndex = key;
                arr.push(key);
            }
        }
        return arr;
    },
    //firstIndex 滚动条顺序是从上到下开始遍历
    itemMoveUp(num) {
        if (num < 0 || this.lastItemIndex + 1 < num || num + 1 > this.itemData.length) {
            return;
        }
        if (!this.hasItem(num)) {
            this.itemMove(num, -this.itemPosMap.get(num).startPos);
        }
        num++;
        return this.itemMoveUp(num);

    },
    //firstIndex 滚动条顺序是从下到上开始遍历
    itemMoveDown(num) {
        if (num < 0 || this.firstItemIndex - 1 > num || num + 1 > this.itemData.length) {
            return;
        }
        if (!this.hasItem(num)) {
            this.itemMove(num, -this.itemPosMap.get(num).startPos);
        }
        num--;
        return this.itemMoveDown(num);

    },
    //判断指定index位置是否存在itemNode.
    hasItem(index) {
        for (let i = 0; i < this.itemArr.length; i++) {
            if (this.itemArr[i].index === index) {
                return true;
            }
        }
        return false;
    },
    //得到要移动的item的索引index,
    //逻辑判断,第一种情况,修改itemArr数组的某个对象,第二种情况实例化一个新itemNode
    itemMove(index, y) {
        for (let i = 0; i < this.itemArr.length; i++) {

            //index存在-3的情况,类似于在缓存池里的item.
            let status1 = this.itemArr[i].index < this.firstItemIndex - 1 ? true : false;
            let status2 = this.itemArr[i].index > this.lastItemIndex + 1 ? true : false;
            let status3 = this.itemArr[i].pfbType === this.itemData[index].pfbType;
            //cc.log('item的索引', this.firstItemIndex, this.lastItemIndex)
            //如果item是展开的状态,不参与排序
            if (this.itemArr[i].isOpen) {
                status1 = false;
                status2 = false;
            }
            if (status1 && status3 || status2 && status3) {
                cc.log(i, index, this.itemArr, this.content.height);
                //给item赋值还有设置位置
                this.itemArr[i].index = index;
                this.itemArr[i].y = y;
                this.itemArr[i].getComponent(cc.Component).init(this.itemData[index], this);
                return;
            }
        }
        this.addItemNode(index, y);
    },
    //得到相关位置的排序index
    getPosIndex(pos) {
        for (let [key, value] of this.itemPosMap.entries()) {
            if (value.endPos > pos && value.startPos <= pos) {
                return key;
            }
        }
    },
    //增加一个item,类似于聊天的时候发信息.
    addItem(obj) {
        this.itemData.push(obj);
        this.getItemPos(0);
        let endPos = this.itemPosMap.get(this.itemData.length - 1).endPos;
        if (endPos - this.layerHeight > 0) {
            let startPos = endPos - this.layerHeight;
            //得到当前的firstItemIndex;
            for (let i = this.itemData.length - 1; i >= 0; i--) {
                if (this.itemPosMap.get(i).endPos > startPos && this.itemPosMap.get(i).startPos <= startPos) {
                    this.firstItemIndex = i;
                }
            }
            this.scrollView.scrollToBottom();
            this.content=this.scrollView.content;
            this.lastItemIndex = this.itemData.length - 1;
            let num = this.firstItemIndex - 1 > 0 ? (this.firstItemIndex - 1) : 0;
            this.itemMoveUp(num);
            return true;
        } else {
            this.firstItemIndex = 0;
            this.lastItemIndex = this.itemData.length - 1;
            this.itemMoveUp(this.firstItemIndex);
            return false;
        }

    },
    //清除界面上的所有item,例如清空聊天信息.
    clearItem() {
        this.itemData = [];
        this.itemPosMap.clear();
        this.scrollView.scrollToTop();
        this.content.height = 0;
        for (let i in this.itemArr) {
            this.itemArr[i].index = -3;
            this.itemArr[i].y = 5000;
        }
    },
    //删除某一条指定item,
    deleteItem(i) {
        this.itemData.splice(i, 1);
        this.getItemPos(0);
        //改变this.itemArr的内容
        for (let j = 0; j < this.itemArr.length; j++) {
            if (this.itemArr[j].index === i) {
                this.itemArr[j].index = -3;
                this.itemArr[j].y = 3000;
            }
            if (this.itemArr[j].index > i) {
                let num = this.itemArr[j].index;
                this.itemArr[j].y = -this.itemPosMap.get(num - 1).startPos;
                this.itemArr[j].index = num - 1;
            }
        }
        this.itemMoveUp(this.firstItemIndex);
    },
    //清空所有item时,把itemData的数据也全部清除.
    resetItemData(index) {
        for (let i = 0; i < this.itemArr.length; i++) {
            if (this.itemArr[i].index === index) {
                let js = this.itemArr[i].getComponent(cc.Component);
                js.init(this.itemData[index], this);
                break;
            }
        }
    },
    //适用于战绩展开的情况
    resetItemSize(index, infoHeight) {
        cc.log(infoHeight)
        let func = (function (index, infoHeight) {
            for (let i = 0; i < this.itemArr.length; i++) {
                //排在点击的node后面的itemNode下移位置.
                if (this.itemArr[i].index > index) {
                    this.itemArr[i].y -= infoHeight;
                }
                //如果相等,表明itemNode已经打开.
                if (this.itemArr[i].index === index) {
                    if (this.itemArr[i].isOpen) {
                        this.itemArr[i].isOpen = false;
                    } else {
                        this.itemArr[i].isOpen = true;
                    }
                } else {
                    if (this.itemArr[i].isOpen) {
                        this.itemArr[i].isOpen = false;
                    }
                }

            }
            //修改位置map的相关数据
            for (let [key, value] of this.itemPosMap.entries()) {
                if (key === index) {
                    value.endPos += infoHeight;
                }
                if (key > index) {
                    value.endPos += infoHeight;
                    value.startPos += infoHeight;
                }
            }
            this.lastResetItemInfoHeight = infoHeight > 0 ? infoHeight : 0;
            this.updateContentHeigh(this.itemPosMap.get(this.itemData.length - 1).endPos);
        }).bind(this);
        if (this.lastResetItemIndex !== null) {
            //如果存在展开的index,判断新点击的node的index是否相同.
            if (this.lastResetItemIndex === index) {
                func(this.lastResetItemIndex, -this.lastResetItemInfoHeight);

                this.lastResetItemIndex = null;
                this.lastResetItemInfoHeight = 0;
            } else {
                cc.log(this.itemArr, this.itemPosMap)
                if (this.lastResetItemIndex < index) {
                    let offset = this.scrollView.getScrollOffset();
                    offset.y -= this.lastResetItemInfoHeight;
                    this.scrollView.scrollToOffset(offset)
                    cc.log(offset)
                }

                func(this.lastResetItemIndex, -this.lastResetItemInfoHeight);
                func(index, infoHeight);
                this.lastResetItemIndex = index;
            }
        } else {
            func(index, infoHeight);
            this.lastResetItemIndex = index;
        }
        //重新获取index,并排序
        this.getItemIndex();
        this.itemMoveUp(this.firstItemIndex);
    },
  destroyItemArr(){
    this.itemArr.forEach((e)=>{
        e.destroy();
    })
    this.itemArr=[];
    this.scrollView.content.height=0;
}

});

demo下载地址http://forum.cocos.com/t/tableview/55795

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 码完的字有形状不多也不少封装起来,贴上标签一并交给远方 像是抛出自己的命运嗖的一声心情,跌入深谷等待黑夜最后的宣判...
    君凉阅读 331评论 18 41
  • 这一个假期最大的收获不是去哪里吃好吃的,也不是去哪里玩的开心的,而是感受到了家里家的感觉增强了。真的好难得,这两天...
    lin秀阅读 150评论 0 0
  • PHP访问MySQL数据库服务器的流程 MySQL采用的是“客户机/服务器”体系结构。可以使用PHP脚本去处理数据...
    dptms阅读 921评论 0 3