/* * @Descripttion: 循环滚动容器 只支持竖向滚动或横向滚动, * @version: 1.0.0 * @Author: YeeChan * @Date: 2020-07-17 10:32:52 */ import FMTouchMaskView, { SlideDirection, FMTouchEvent } from "./FMTouchMaskView"; import { FMListener, callFM_custom, handleFM_custom } from "../Interface/FMInterface"; import Utilit from "../Util/Utilit"; import FMItemLayout from "./FMItemLayout"; const { ccclass, property, requireComponent, disallowMultiple, menu } = cc._decorator; @ccclass // @requireComponent(cc.ScrollView) @disallowMultiple() //防止多个相同类型(或子类型)的组件被添加到同一个节点 //@menu('FM组件/FMScrollViewLoop') export default class FMScrollViewLoop extends FMTouchMaskView { //是否自动移动 @property() private _isAutoMoveType: boolean = true; @property({ tooltip: "自动滚动", type: cc.Boolean }) set isAutoMoveType(val: boolean) { this._isAutoMoveType = val; } get isAutoMoveType() { return this._isAutoMoveType; } //-------------------------------------- //广告标签 protected ad_tag_custom: any; //更新的回调 protected fmListenerUpdateData_custom: FMListener; //layout list protected arrayAliveListLayout_custom: FMItemLayout[] = [] //自由的节点 protected arrayFreeListLayout_custom: FMItemLayout[] = [] //一个屏幕中的layout数量 private viewLayoutNum_custom: number = 0; //超出的个数 private viewLayoutGapNum_custom: number = 3; //总共的个数 private viewLayoutSum_custom: number = 0; //初始的下标 private startIndexItem_custom: number = 0; //是否可以更新item相关 private isCanUpdateItems_custom: boolean = false; //点击了 触发停止 private isTouchStop_custom: boolean = false; //外部需要控制的是否可以update private _isCanScrollViewLoopUpdate_custom: boolean = true; protected isAutoMoveWayLeftUp_custom: boolean = true;//是否自动移动往左或上 还是右或下 //自动移动后等待的时间 protected autoMoveWaitTime_custom: number = 60; //自动移动的一次的距离格子数量 0不启用 protected autoMoveWaitNum_custom: number = 1; //移动的数据 protected autoMoveSpeed_custom: number = 3; // //当次移动的距离大小 private _nextMoveLength_custom: number = 0; //当下需要等待的时间 private _waitTimeNum_custom: number = 0; private _moveState_custom: number = 0;//0正常移动 1等待 protected _init_custom(): boolean { if (super._init_custom()) { if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 this.viewLayoutNum_custom = Math.ceil(this.node.width / (this.itemPrefabWidth_custom)); } else if (this._slideDirection == SlideDirection.VERTICAL) {//垂直 this.viewLayoutNum_custom = Math.ceil(this.node.width / (this.itemPrefabHeight_custom)); } //创建的个数 this.viewLayoutSum_custom = this.viewLayoutNum_custom + this.viewLayoutGapNum_custom * 2 let pos = 0; for (let index = 0; index < this.viewLayoutSum_custom; index++) { let layoutScript = this.cloneLayout_custom(); let layout = layoutScript.node; if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 layout.x = pos; layout.y = 0; pos = pos + layout.width; } else if (this._slideDirection == SlideDirection.VERTICAL) {//垂直 layout.x = 0; layout.y = pos; pos = pos - layout.height } this.arrayAliveListLayout_custom.push(layoutScript); } this.isCanUpdateItems_custom = true; return true; } return false; } /** * 外部调用 * @param _listener */ public setFMListenerUpdateItem_custom(_listener: FMListener) { this.fmListenerUpdateData_custom = _listener; } /** * 设置自动移动的数据 * @param way 方向 * @param moveWaitNum 移动的格子 0持续 * @param waitTime 移动的格子后停顿的时间 s * @param speed 速度 */ public setAutoData_custom(way: number, moveWaitNum?: number, waitTime?: number, speed?: number, bgColor?: string) { this.isAutoMoveWayLeftUp_custom = way == 0 ? true : false; this.autoMoveWaitNum_custom = moveWaitNum ? Math.abs(moveWaitNum) : 0; this.autoMoveWaitTime_custom = waitTime ? Math.abs(waitTime) * 60 : 60; this.autoMoveSpeed_custom = speed ? Math.abs(speed) : 3; if (bgColor) { this.node.color = Utilit.colorHex2Rgb_custom(bgColor); } } /** * 是否点击了 */ public isTouchStopView_custom() { return this.isTouchStop_custom; } /** * 外部控制是否update */ public setCanScrollViewLoopUpdate_custom(_update: boolean) { this._isCanScrollViewLoopUpdate_custom = _update; } /** * 设置广告的自定义标签 * @param tag */ public setAdTag_custom(tag: any) { this.ad_tag_custom = tag; for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; element.setAdTag_custom(this.ad_tag_custom); } for (let index = 0; index < this.arrayFreeListLayout_custom.length; index++) { const element = this.arrayFreeListLayout_custom[index]; element.setAdTag_custom(this.ad_tag_custom); } } //外部初始数据 public initUpdateItems_custom() { this._init_custom(); this.startIndexItem_custom = 0; if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 let pos = - this.itemPrefabWidth_custom * 3; for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; element.setPointX_custom(pos); element.setItemIndex_custom(this.startIndexItem_custom + index); pos = pos + this.itemPrefabWidth_custom } } else { //垂直 let pos = this.itemPrefabHeight_custom * 3; for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; element.setPointY_custom(pos); element.setItemIndex_custom(this.startIndexItem_custom + index); pos = pos - this.itemPrefabHeight_custom } } this._updateNextLengthTime_custom(); } protected update(dt: number): void { if (this.isCanUpdateItems_custom && this._isCanScrollViewLoopUpdate_custom) { this.updateScrollingItems_custom(); if (this.isAutoMoveType == true) {//判断类型是自动移动类型 this._updateAutoMove_custom(); } } } /** * 更新子节点的数据内容 * @param index 第几个大的 * @param childIndex 第几个小的 */ protected listenerUpdateInitItem_custom(sum: number) { if (this.fmListenerUpdateData_custom) { let data = callFM_custom(this.fmListenerUpdateData_custom, sum); return data; } } /** * 自动移动 */ public _updateAutoMove_custom() { if (this.isTouchStopView_custom()) { return; } if (this._moveState_custom == 0) { if (this.isAutoMoveWayLeftUp_custom) { if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 this.content_custom.x = this.content_custom.x - this.autoMoveSpeed_custom } else { this.content_custom.y = this.content_custom.y + this.autoMoveSpeed_custom } } else { if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 this.content_custom.x = this.content_custom.x + this.autoMoveSpeed_custom } else { this.content_custom.y = this.content_custom.y - this.autoMoveSpeed_custom } } if (this.autoMoveWaitNum_custom > 0) {//0 持续移动 this._nextMoveLength_custom = this._nextMoveLength_custom - this.autoMoveSpeed_custom; if (this._nextMoveLength_custom <= 0) { this._moveState_custom = 1; } } } else { this._waitTimeNum_custom = this._waitTimeNum_custom + 1; if (this._waitTimeNum_custom >= this.autoMoveWaitTime_custom) { this._waitTimeNum_custom = 0; this._updateNextLengthTime_custom(); } } } /** * 消息 * @param event */ protected _dispatchEvent_custom(event: FMTouchEvent) { if (event == FMTouchEvent.Scrolling) { //this.updateScrollingItems(); } else if (event == FMTouchEvent.TouchStart) { this.isTouchStop_custom = true; } else if (event == FMTouchEvent.TouchEnded) { this._updateNextLengthTime_custom(); this.isTouchStop_custom = false; } } /** * 更新下次移动需要的数据 */ protected _updateNextLengthTime_custom() { if (this.autoMoveWaitNum_custom > 0) { if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 this._nextMoveLength_custom = this.autoMoveWaitNum_custom * this.itemPrefab.data.width if (this.isAutoMoveWayLeftUp_custom) { for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; let vcx = this.content_custom.x + element.node.x; if (vcx > -element.node.width && vcx < 0) { this._nextMoveLength_custom = this._nextMoveLength_custom + vcx; break; } } } else { for (let index = this.arrayAliveListLayout_custom.length - 1; index >= 0; index--) { const element = this.arrayAliveListLayout_custom[index]; let vcx = this.content_custom.x + element.node.x; if (vcx < this.node.width + element.node.width && vcx > this.node.width) { vcx = vcx - this.node.width; this._nextMoveLength_custom = this._nextMoveLength_custom - vcx; break; } } } } else {//垂直 this._nextMoveLength_custom = this.autoMoveWaitNum_custom * this.itemPrefab.data.height if (this.isAutoMoveWayLeftUp_custom) { for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; let vcy = this.content_custom.y + element.node.y; if (vcy < element.node.height && vcy > 0) { this._nextMoveLength_custom = this._nextMoveLength_custom - vcy; break; } } } else { for (let index = this.arrayAliveListLayout_custom.length - 1; index >= 0; index--) { const element = this.arrayAliveListLayout_custom[index]; let vcy = this.content_custom.y + element.node.y - element.node.height; if (vcy > -(this.node.height + element.node.height) && vcy < -this.node.height) { vcy = vcy + this.node.height; this._nextMoveLength_custom = this._nextMoveLength_custom + vcy; break; } } } } } this._waitTimeNum_custom = 0; this._moveState_custom = 0; } //更新 protected updateScrollingItems_custom() { let arrayLive: FMItemLayout[] = [] if (this._slideDirection == SlideDirection.HORIZONTAL) {//水平 for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; if (this.content_custom.x + element.getPointX_custom() < - this.itemPrefabWidth_custom * 3) {//左 超过三个标准 移除 this.addFreeItem_custom(element); } else if (element.getPointX_custom() + this.content_custom.x > this.node.width + this.itemPrefabWidth_custom * 3) { //右 超过三个标准 移除 this.addFreeItem_custom(element); } else { //中间区域 激活 arrayLive.push(element); } } if (arrayLive[0].getPointX_custom() + this.content_custom.x > - this.itemPrefabWidth_custom) {//起始的 低于一个标准 创建一个 let element = this.getFreeItem_custom(); element.setPointX_custom(arrayLive[0].getPointX_custom() - this.itemPrefabWidth_custom); element.setItemIndex_custom(arrayLive[0].getItemIndex_custom() - 1) arrayLive.splice(0, 0, element); element.node.active = true; } if (arrayLive[arrayLive.length - 1].getPointX_custom() + this.content_custom.x < + this.node.width + this.itemPrefabWidth_custom) {//结尾的 低于一个标准 创建一个 const element = this.getFreeItem_custom() element.setPointX_custom(arrayLive[arrayLive.length - 1].getPointX_custom() + this.itemPrefabWidth_custom); element.setItemIndex_custom(arrayLive[arrayLive.length - 1].getItemIndex_custom() + 1) arrayLive.push(element); element.node.active = true; } } else { //垂直 for (let index = 0; index < this.arrayAliveListLayout_custom.length; index++) { const element = this.arrayAliveListLayout_custom[index]; if (element.getPointY_custom() + this.content_custom.y > this.itemPrefabHeight_custom * 3) {//上 超过三个标准 移除 this.addFreeItem_custom(element); } else if (element.getPointY_custom() < -(this.content_custom.y + this.node.height + this.itemPrefabHeight_custom * 3)) { //下 超过三个标准 移除 this.addFreeItem_custom(element); } else { //中间区域 激活 arrayLive.push(element); } } if (arrayLive[0].getPointY_custom() + this.content_custom.y <= this.itemPrefabHeight_custom) {//起始的 低于一个标准 创建一个 let element = this.getFreeItem_custom(); element.setPointY_custom(arrayLive[0].getPointY_custom() + this.itemPrefabHeight_custom); element.setItemIndex_custom(arrayLive[0].getItemIndex_custom() - 1) arrayLive.splice(0, 0, element); element.node.active = true; } if (arrayLive[arrayLive.length - 1].getPointY_custom() >= -(this.content_custom.y + this.node.height + this.itemPrefabHeight_custom)) {//结尾的 低于一个标准 创建一个 const element = this.getFreeItem_custom() element.setPointY_custom(arrayLive[arrayLive.length - 1].getPointY_custom() - this.itemPrefabHeight_custom); element.setItemIndex_custom(arrayLive[arrayLive.length - 1].getItemIndex_custom() + 1) arrayLive.push(element); element.node.active = true; } } this.arrayAliveListLayout_custom = arrayLive; } /** * 创建一个 */ private cloneLayout_custom(): FMItemLayout { let layout = cc.instantiate(this.itemPrefab); let script = layout.getComponent(FMItemLayout); script.setAdTag_custom(this.ad_tag_custom) script.setFMListenerUpdate_custom(handleFM_custom(this.listenerUpdateInitItem_custom, this)); this.content_custom.addChild(layout); return script; } /** * 获取一个自由节点 */ private getFreeItem_custom(): FMItemLayout { let element = this.arrayFreeListLayout_custom.pop() if (!element) { element = this.cloneLayout_custom(); } return element; } private addFreeItem_custom(item: FMItemLayout) { item.node.active = false; this.arrayFreeListLayout_custom.push(item); } }