123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- import SuperListItem from "./SuperListItem";
- const { ccclass, property } = cc._decorator;
- @ccclass
- export default class SuperScrollView extends cc.ScrollView {
- @property({
- type: cc.Node,
- tooltip: 'item模板',
- })
- pfItemTemplate: cc.Node = null;
- itemSize: cc.Size = null;
- itemNodePool: cc.NodePool = null;
- @property({
- tooltip: '分帧加载时间间隔',
- })
- duration: number = 1;
- // @property({
- // tooltip: '最多可以显示多少个Item',
- // })
- visibleNum: number = 12;
- private curIndex: number = 0;
- private itemInfoList: any[] = [];
- private isFrameLoading: boolean = false;
- private isLoadingFinished: boolean = true;
- private cbAfterSetData: Function = null;
- private lastTime: number = 0;
- onLoad() {
- this.elastic = true;
- this.content.on(cc.Node.EventType.CHILD_ADDED, this.childAdded.bind(this));
- this.node.on("touchend", this.onTouchEnd, this);
- this.node.on("scroll-ended", this.onScrollEnded, this);
- this.node.on("scrolling", this.onScrolling, this);
- this.node.on("bounce-top", this.onBounceTop, this);
- this.node.on("bounce-bottom", this.onBounceBottom, this);
- this.node.on("bounce-left", this.onBounceLeft, this);
- this.node.on("bounce-right", this.onBounceRight, this);
- this.initNodePool();
- }
- onDestroy() {
- this.content.off(cc.Node.EventType.CHILD_ADDED, this.childAdded);
- this.node.off("touchend", this.onTouchEnd, this);
- this.node.off("scroll-ended-with-threshold", this.onScrollEnded, this);
- this.node.off("scrolling", this.onScrolling, this);
- this.node.off("bounce-top", this.onBounceTop, this);
- this.node.off("bounce-bottom", this.onBounceBottom, this);
- this.node.off("bounce-left", this.onBounceLeft, this);
- this.node.off("bounce-right", this.onBounceRight, this);
- }
- private initNodePool() {
- let itemNode = cc.instantiate(this.pfItemTemplate);
- let contentSize = itemNode.getContentSize();
- this.itemSize = contentSize;
- let parentSize = this.content.parent.getContentSize();
- let layoutComp = this.content.getComponent(cc.Layout);
- let num = 0;
- if (layoutComp) {
- if (layoutComp.type === cc.Layout.Type.VERTICAL && this.vertical && !this.horizontal) {
- num = Math.ceil(parentSize.height / contentSize.height);
- } else if (layoutComp.type === cc.Layout.Type.HORIZONTAL && this.horizontal && this.vertical) {
- num = Math.ceil(parentSize.width / contentSize.width);
- } else if (layoutComp.type === cc.Layout.Type.GRID) {
- let rowEleCount = Math.floor((parentSize.width - layoutComp.paddingLeft - layoutComp.paddingRight + layoutComp.spacingX) / (contentSize.width + layoutComp.spacingX))
- let colEleCount = Math.floor((parentSize.height - layoutComp.paddingTop - layoutComp.paddingBottom + layoutComp.spacingY) / (contentSize.height + layoutComp.spacingY))
- num = rowEleCount * colEleCount;
- // console.log('最多显示个数:GRID', rowEleCount, colEleCount);
- }
- }
- this.visibleNum = Math.floor(num * 2) + 2;
- // console.log('最多显示个数', this.visibleNum);
- if (this.itemNodePool) {
- //清空
- this.itemNodePool.clear();
- } else {
- this.itemNodePool = new cc.NodePool();
- }
- //多放3个
- for (let i = 0; i < this.visibleNum + 3; i++) {
- let itemNode = cc.instantiate(this.pfItemTemplate);
- this.itemNodePool.put(itemNode);
- }
- }
- //添加节点
- private childAdded(itemNode: cc.Node) {
- this.curIndex++;
- itemNode.name = "item" + this.curIndex;
- }
- public scrollToIndex(index: number, seconds: number = 0.2) {
- // cc.log("index:", index);
- let childCount = this.content.childrenCount;
- // cc.log("childCount:", childCount);
- if (index < 1) {
- // cc.log("index 过小");
- index = 1;
- }
- else if (index > childCount) {
- // cc.log("index 过大");
- index = childCount;
- }
- let item = this.content.getChildByName('item' + index);
- if (item) {
- let layoutComp: cc.Layout = this.content.getComponent(cc.Layout);
- if (layoutComp) {
- if (layoutComp.type === cc.Layout.Type.VERTICAL && this.vertical && !this.horizontal) {
- this.scrollToPercentVertical((childCount - index) / childCount, seconds);
- } else if (layoutComp.type === cc.Layout.Type.HORIZONTAL && !this.vertical && this.horizontal) {
- this.scrollToPercentHorizontal((childCount - index) / childCount, seconds);
- } else if (layoutComp.type === cc.Layout.Type.GRID) {
- if (layoutComp.startAxis === cc.Layout.AxisDirection.HORIZONTAL) {
- let contentSize = this.content.getContentSize();
- let itemContentSize = item.getContentSize();
- // contentSize.width = layoutComp.paddingLeft + layoutComp.paddingRight + itemContentSize.width * n + layoutComp.spacingX *(n-1)
- let rowEleCount = Math.floor((contentSize.width - layoutComp.paddingLeft - layoutComp.paddingRight + layoutComp.spacingX) / (itemContentSize.width + layoutComp.spacingX))
- // cc.log("每行多少个:", rowEleCount);
- let hang = Math.ceil(index / rowEleCount);
- let totalHang = Math.ceil(childCount / rowEleCount);
- this.scrollToPercentVertical((totalHang - hang) / totalHang, seconds);
- } else {
- let contentSize = this.content.getContentSize();
- let itemContentSize = item.getContentSize();
- let colEleCount = Math.floor((contentSize.height - layoutComp.paddingTop - layoutComp.paddingBottom + layoutComp.spacingY) / (itemContentSize.height + layoutComp.spacingY))
- // cc.log("每列多少个:", colEleCount);
- let lie = Math.ceil(index / colEleCount);
- let totalLie = Math.ceil(childCount / colEleCount);
- this.scrollToPercentHorizontal((totalLie - lie) / totalLie, seconds);
- }
- } else {
- // cc.log("cc.Layout.Type不对");
- }
- }
- }
- }
- private onTouchEnd() {
- return;
- this.improveDC();
- }
- private onScrollEnded() {
- // cc.log("onScrollEnded");
- this.improveDC();
- }
- private onScrolling() {
- let now = Date.now();
- if (now - this.lastTime < 200) {
- return;
- }
- // cc.log("scolling");
- this.lastTime = now;
- let scrollOffset = this.getScrollOffset();
- let offsetX = scrollOffset.x;
- let offsetY = scrollOffset.y;
- this.improveDC();
- }
- private onBounceTop() {
- // cc.log("onBounceTop")
- }
- private onBounceBottom() {
- // cc.log("onBounceBottom")
- }
- private onBounceLeft() {
- // cc.log("onBounceLeft")
- }
- private onBounceRight() {
- // cc.log("onBounceLeft")
- }
- private newItemNode(): cc.Node {
- // let itemNode = this.itemNodePool.get();
- // if (!itemNode) {
- // cc.log("instantiate");
- // itemNode = cc.instantiate(this.pfItemTemplate);
- // }
- let itemNode = cc.instantiate(this.pfItemTemplate);
- return itemNode;
- }
- // 优化DrawCall
- public improveDC() {
- if (this.content.childrenCount == 0) {
- return;
- }
- let svLeftBottomPoint: cc.Vec2 = this.node.parent.convertToWorldSpaceAR(
- // cc.v2(0,0)
- cc.v2(
- this.node.x - this.node.anchorX * this.node.width,
- this.node.y - this.node.anchorY * this.node.height
- )
- );
- // 求出 ScrollView 可视区域在世界坐标系中的矩形(碰撞盒)
- let svBBoxRect: cc.Rect = cc.rect(svLeftBottomPoint.x, svLeftBottomPoint.y, this.node.width, this.node.height);
- // 遍历 ScrollView Content 内容节点的子节点,对每个子节点的包围盒做和 ScrollView 可视区域包围盒做碰撞判断
- this.content.children.forEach((childNode: cc.Node) => {
- // 如果相交了,那么就显示,否则就隐藏
- let childNodeBBox = childNode.getBoundingBoxToWorld();
- if (childNodeBBox.intersects(svBBoxRect)) {
- if (childNode.opacity === 0) {
- childNode.opacity = 255;
- }
- } else {
- if (childNode.opacity !== 0) {
- childNode.opacity = 0;
- }
- }
- });
- }
- public async setData(itemInfoList: any[], isFrameLoading: boolean = false, cb?: Function) {
- if (!this.isLoadingFinished) {
- return;
- }
- this.curIndex = 0;
- this.isLoadingFinished = false;
- this.isFrameLoading = isFrameLoading;
- this.itemInfoList = itemInfoList;
- this.cbAfterSetData = cb;
- this.content.destroyAllChildren();
- if (this.isFrameLoading) {
- await this.executePreFrame(this.getItemGenerator(this.itemInfoList.length), this.duration);
- } else {
- for (let i = 0; i < this.itemInfoList.length; i++) {
- let item = this.newItemNode();
- item.parent = this.content;
- item.getComponent(SuperListItem).setData(itemInfoList[i]);
- }
- this.isLoadingFinished = true;
- this.scheduleOnce(() => {
- this.cbAfterSetData && this.cbAfterSetData();
- this.improveDC();
- });
- }
- }
- //@ts-ignore
- private executePreFrame(generator: Generator, duration: number) {
- return new Promise((resolve, reject) => {
- let gen = generator;
- // 创建执行函数
- let execute = () => {
- // 执行之前,先记录开始时间
- let startTime = new Date().getTime();
- // 然后一直从 Generator 中获取已经拆分好的代码段出来执行
- for (let iter = gen.next(); ; iter = gen.next()) {
- // 判断是否已经执行完所有 Generator 的小代码段,如果是的话,那么就表示任务完成
- if (iter == null || iter.done) {
- //@ts-ignore
- resolve();
- return;
- }
- // 每执行完一段小代码段,都检查一下是否已经超过我们分配的本帧,这些小代码端的最大可执行时间
- if (new Date().getTime() - startTime > duration) {
- // 如果超过了,那么本帧就不在执行,开定时器,让下一帧再执行
- this.scheduleOnce(() => {
- execute();
- });
- return;
- }
- }
- };
- // 运行执行函数
- execute();
- });
- }
- private initItem(itemInfo: any) {
- let itemNode = this.newItemNode();
- itemNode.parent = this.content;
- itemNode.getComponent(SuperListItem).setData(itemInfo);
- }
- private *getItemGenerator(length: number) {
- for (let i = 0; i < length; i++) {
- yield this.initItem(this.itemInfoList[i]);
- }
- this.isLoadingFinished = true;
- this.scheduleOnce(() => {
- this.cbAfterSetData && this.cbAfterSetData();
- this.improveDC();
- });
- }
- public canInputData(): boolean {
- return this.isLoadingFinished;
- }
- //通过index去获取节点
- public getItem(index: number): cc.Node {
- let item = this.content.getChildByName('item' + index);
- return item || null;
- }
- // update (dt) {}
- }
|