const { ccclass, property, menu, executionOrder } = cc._decorator;
@ccclass
@menu('自定义组件/PageList')
@executionOrder(-100)
export default class PageList extends cc.Component {
@property()
private circulate = true;
@property(cc.Node)
tempItem: cc.Node = nn<cc.Node>();
@property(cc.Node)
slideParent: cc.Node = nn<cc.Node>();
// 刷新某页信息
@property(cc.Component.EventHandler)
pageChangeEvent: cc.Component.EventHandler = new cc.Component.EventHandler();
// 切换到某一页
@property(cc.Component.EventHandler)
pageRefreshEvent: cc.Component.EventHandler = new cc.Component.EventHandler();
@property(cc.Integer)
offset = 0;
// 滑动距离与节点宽度比超过多少触发切换
@property(cc.Float)
switchPercent = 0.2;
private isInit = false;
private pageLeft: cc.Node = nn<cc.Node>();
private pageRight: cc.Node = nn<cc.Node>();
private pageCenter: cc.Node = nn<cc.Node>();
private _curPageIndex = 0;
private set curPageIndex(value: number) {
this._curPageIndex = value;
this.onRefreshPageIndex();
}
private get curPageIndex() {
return this._curPageIndex;
}
private pageCnt = 0;
private curTargetX = 0;
private switchDistance = 0;
override onLoad() {
this.onInit();
}
onInit() {
if (!this.isInit) {
this.isInit = true;
this.pageLeft = this.createPageItem();
this.pageRight = this.createPageItem();
this.pageCenter = this.tempItem;
this.tempItem.active = false;
this.switchDistance = this.node.width * this.switchPercent;
this.registerEvent();
}
}
createPageItem() {
const node = cc.instantiate(this.tempItem);
node.parent = this.slideParent;
node.active = false;
return node;
}
onRefreshList(showIndex: number, length: number) {
if (showIndex >= length) {
showIndex %= length;
}
this.pageCnt = length;
this.curPageIndex = showIndex;
this.slideParent.setPosition(0, 0);
this.onRefreshPageInfo(this.pageCenter, showIndex);
this.pageCenter.setPosition(0, 0);
this.curTargetX = 0;
const leftIndex = this.getLeftIndex(showIndex);
if (leftIndex !== null) {
this.onRefreshPageInfo(this.pageLeft, leftIndex);
this.pageLeft.setPosition(-this.tempItem.width - this.offset, 0);
} else {
this.pageLeft.active = false;
}
const rightIndex = this.getRightIndex(showIndex);
if (rightIndex !== null) {
this.onRefreshPageInfo(this.pageRight, rightIndex);
this.pageRight.setPosition(this.tempItem.width + this.offset, 0);
} else {
this.pageRight.active = false;
}
cc.Tween.stopAllByTarget(this.slideParent);
}
onRefreshPageInfo(target: cc.Node, index: number) {
target.active = true;
if (this.pageChangeEvent) {
cc.Component.EventHandler.emitEvents([this.pageChangeEvent], target, index);
}
}
onRefreshPageIndex() {
if (this.pageRefreshEvent) {
cc.Component.EventHandler.emitEvents([this.pageRefreshEvent], this.curPageIndex);
}
}
private getLeftIndex(centerIndex: number) {
let index = centerIndex - 1;
if (index < 0 && this.circulate) {
index = this.pageCnt - 1;
}
return index < 0 ? null : index;
}
private getRightIndex(centerIndex: number) {
let index = centerIndex + 1;
if (index >= this.pageCnt && this.circulate) {
index = 0;
}
return index >= this.pageCnt ? null : index;
}
private touchStartX = 0;
private contentStartX = 0;
private touchFlag = false;
private slideAnimation = false;
onTouchStart(event: cc.Event.EventTouch) {
if (this.slideAnimation) return;
this.touchFlag = true;
this.touchStartX = event.getLocationX();
this.contentStartX = this.slideParent.x;
this.isChanged = false;
}
private isChanged = false;
private isChangeRight = false;
onTouchMove(event: cc.Event.EventTouch) {
if (!this.touchFlag) return;
this.slideParent.setPosition(
this.contentStartX + event.getLocationX() - this.touchStartX,
0
);
const moveDistance = this.contentStartX - this.slideParent.x;
if (
Math.abs(moveDistance) >
this.tempItem.width - (this.node.width - this.tempItem.width) / 2
) {
if (!this.isChanged) {
this.isChanged = true;
if (moveDistance > 0) {
this.isChangeRight = true;
this.onFocusRight();
} else {
this.isChangeRight = false;
this.onFocusLeft();
}
}
return;
}
if (this.isChanged) {
this.isChanged = false;
this.isChangeRight ? this.onFocusLeft() : this.onFocusRight();
}
}
onTouchEnd() {
if (!this.touchFlag) return;
this.touchFlag = false;
this.slideAnimation = true;
const slideDistance = this.curTargetX - this.slideParent.x;
if (Math.abs(slideDistance) >= this.switchDistance)
if (slideDistance > 0 && this.pageRight.active) {
this.onFocusRight();
} else if (slideDistance < 0 && this.pageLeft.active) {
this.onFocusLeft();
}
cc.tween(this.slideParent)
.to(Math.abs(this.curTargetX - this.slideParent.x) / 1000, {
x: this.curTargetX,
})
.call(() => {
this.slideAnimation = false;
})
.start();
}
private onFocusRight() {
this.curTargetX = this.curTargetX - this.tempItem.width - this.offset;
const changeNode = this.pageLeft;
this.pageLeft = this.pageCenter;
this.pageCenter = this.pageRight;
this.pageRight = changeNode;
this.curPageIndex = this.getRightIndex(this.curPageIndex) || 0;
const nextIndex = this.getRightIndex(this.curPageIndex);
if (nextIndex !== null) {
this.pageRight.setPosition(this.pageCenter.x + this.tempItem.width + this.offset, 0);
this.onRefreshPageInfo(this.pageRight, nextIndex);
} else {
this.pageRight.active = false;
}
}
private onFocusLeft() {
this.curTargetX = this.curTargetX + this.tempItem.width + this.offset;
const changeNode = this.pageRight;
this.pageRight = this.pageCenter;
this.pageCenter = this.pageLeft;
this.pageLeft = changeNode;
this.curPageIndex = this.getLeftIndex(this.curPageIndex) || 0;
const nextIndex = this.getLeftIndex(this.curPageIndex);
if (nextIndex !== null) {
this.pageLeft.setPosition(this.pageCenter.x - this.tempItem.width - this.offset, 0);
this.onRefreshPageInfo(this.pageLeft, nextIndex);
} else {
this.pageLeft.active = false;
}
}
registerEvent() {
this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this, true);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this, true);
this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this, true);
this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this, true);
}
unregisterEvent() {
this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this, true);
this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this, true);
this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this, true);
this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this, true);
}
}
10-18
1882
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
05-21
901
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
08-18
1077
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
04-27