class ListViewAdapter { constructor(scrollView) { this.scrollView = scrollView; this.content = scrollView.content; this.scriptItems = []; this.dataList = []; // this.initialize(); this.updateTimer = 0; this.updateInterval = 0.1; this.lastContentPosY = 0; // use this variable to detect if we are scrolling up or down this.spawnCount = 12; this.itemHeight = 0; this.bufferZone = 500; this.spacing = 10; this.scriptName = ''; this.fuckingItem = null; } initialize(itemTemplate) { // console.log(this.scriptName); let actualCount = this.dataList.length < this.spawnCount ? this.dataList.length : this.spawnCount; // let actualCount = this.dataList.length; this.scriptItems = []; this.content.removeAllChildren(); for (let i = 0; i < actualCount; ++i) { // spawn items, we only need to do this once let item = cc.instantiate(itemTemplate); if (this.itemHeight === 0) { this.itemHeight = item.height; // get total content height } this.content.addChild(item); item.setPosition(0, -item.height * (0.5 + i) - this.spacing * (i + 1)); let itemScript = item.getComponent(this.scriptName); itemScript.setListViewAdapter(this); itemScript.updateItem(this.dataList[i], i); this.scriptItems.push(itemScript); } this.content.height = (this.itemHeight + this.spacing) * this.dataList.length; } getPositionInView(item) { // get item position in scrollview's node space 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; // we don't need to do the math every frame this.updateTimer = 0; let buffer = this.bufferZone; let isDown = this.content.y < this.lastContentPosY; // scrolling direction let offset = (this.itemHeight + this.spacing) * this.scriptItems.length; for (let i = 0; i < this.scriptItems.length; ++i) { let viewPos = this.getPositionInView(this.scriptItems[i].node); let itemY = this.scriptItems[i].node.y; if (isDown) { // if away from buffer zone and not reaching top of content if (viewPos.y < -buffer && itemY + offset < 0) { this.scriptItems[i].node.setPosition(0, itemY + offset); let itemScript = this.scriptItems[i]; let itemId = itemScript._itemId - this.scriptItems.length; itemScript.updateItem(this.dataList[itemId], itemId); } } else { // if away from buffer zone and not reaching bottom of content if (viewPos.y > buffer && itemY - offset > -this.content.height) { this.scriptItems[i].node.setPosition(0, itemY - offset); let itemScript = this.scriptItems[i]; let itemId = itemScript._itemId + this.scriptItems.length; itemScript.updateItem(this.dataList[itemId], itemId); if (itemId === (this.dataList.length - 1)) { if (this.loadMore != undefined) { this.loadMore(); } } } } } // update lastContentPosY this.lastContentPosY = this.content.y; } updateItems(dataList, itemPrefab, scriptName) { this.scriptName = scriptName; this.itemTemplate = itemPrefab; this.dataList = dataList; this.initialize(itemPrefab); } addData(newdataList) { this.dataList = this.dataList.concat(newdataList); this.content.height = (this.itemHeight + this.spacing) * this.dataList.length; // get total content height } setLoadMoreCallBack(loadMore) { this.loadMore = loadMore; } playRemoveItemAnimation(itemScript, animCallback) { this.dataList.splice(itemScript._itemId, 1); this.content.height = (this.itemHeight + this.spacing) * this.dataList.length; // get total content height let sequ = cc.sequence(cc.moveBy(0.2, -750, 0), animCallback); itemScript.node.runAction(sequ); } updateItemsAndDataList(itemScript) { let index = itemScript._itemId; let scriptItems = this.scriptItems; if (this.dataList.length >= scriptItems.length) { itemScript.scheduleOnce(() => { itemScript.node.x = 0; }, 0.2); for (let i = 0; i < scriptItems.length; ++i) { let itemNode = scriptItems[i].node; let script = scriptItems[i]; let itemId = script._itemId; if (itemId < this.dataList.length) { if (script._itemId > index) { let finish = cc.callFunc(() => { itemNode.y = itemNode.y - (this.itemHeight + this.spacing); script.updateItem(this.dataList[itemId], itemId); }, this); let s = cc.sequence(cc.moveBy(0.2, 0, (this.itemHeight + this.spacing)), finish); itemNode.runAction(s); } else { itemScript.scheduleOnce(() => { script.updateItem(this.dataList[itemId], itemId); }, 0.2); } } } } else { for (let i = 0; i < scriptItems.length; ++i) { let itemId = scriptItems[i]._itemId; if (itemId === itemScript._itemId) { this.scriptItems.splice(i, 1); } } for (let i = 0; i < scriptItems.length; ++i) { let itemNode = scriptItems[i].node; let script = scriptItems[i]; if (script._itemId > index) { let newId = script._itemId - 1; itemNode.runAction(cc.moveBy(0.2, 0, (this.itemHeight + this.spacing))); script.updateItem(this.dataList[newId], newId); } } itemScript.node.destroy(); } } removeItem(itemScript) { let finish = cc.callFunc(() => { this.updateItemsAndDataList(itemScript); }); this.playRemoveItemAnimation(itemScript, finish); } onDestroy() { this.scriptItems = []; this.content.removeAllChildren(); } } module.exports = ListViewAdapter;