338 lines
9.8 KiB
TypeScript
338 lines
9.8 KiB
TypeScript
import { _decorator, Camera, Component, director, EventMouse, EventTouch, math, Node, ScrollView, UITransform, Vec2, Vec3 } from 'cc';
|
||
import { hideAllChildren, showAllChildren } from './Tools';
|
||
const { ccclass, property } = _decorator;
|
||
|
||
enum SCROLL_TYPE {
|
||
NULL,
|
||
HORIZONTAL,
|
||
VERTICAL,
|
||
}
|
||
|
||
@ccclass('ScrollControl')
|
||
export class ScrollControl extends Component {
|
||
|
||
/*
|
||
<ScrollView 横向>
|
||
├── <Item 1 (纵向ScrollView)>
|
||
├── <Item 2 (纵向ScrollView)>
|
||
├── <Item 3 (纵向ScrollView)>
|
||
...
|
||
*/
|
||
|
||
/**横向的scrollView*/
|
||
@property(ScrollView)
|
||
hor_scrollView: ScrollView = null;
|
||
|
||
@property(Node)
|
||
item_detail: Node = null;
|
||
|
||
@property(Node)
|
||
flip: Node = null;
|
||
|
||
node_history_detail: Node = null;
|
||
vert_scrollView: ScrollView = null;
|
||
curSelectFormula: Node = null;
|
||
|
||
scrollSpeed = 100;
|
||
|
||
private _touchLastPos: { x: number, y: number } | null = null;
|
||
|
||
private page = 0
|
||
|
||
|
||
/**当前滚动方向*/
|
||
private _curScrollType: SCROLL_TYPE = SCROLL_TYPE.NULL;
|
||
|
||
onLoad() {
|
||
this.node_history_detail = this.node.parent
|
||
|
||
this.node.on(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
||
this.node.on(Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
|
||
this.node.on(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
||
this.node.on(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this);
|
||
|
||
this.node.on(Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
|
||
}
|
||
|
||
onDisable() {
|
||
this.node.off(Node.EventType.TOUCH_START, this._onTouchStart, this);
|
||
this.node.off(Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
|
||
this.node.off(Node.EventType.TOUCH_END, this._onTouchEnd, this);
|
||
this.node.off(Node.EventType.TOUCH_CANCEL, this._onTouchEnd, this);
|
||
this.node.off(Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
|
||
}
|
||
|
||
protected start(): void {
|
||
this.checkPageBtn()
|
||
}
|
||
|
||
|
||
private _onTouchStart(event: EventTouch) {
|
||
// // console.log("_onTouchStart")
|
||
|
||
event.propagationStopped = false
|
||
|
||
const touchPos = event.getUILocation();
|
||
this._touchLastPos = { x: touchPos.x, y: touchPos.y };
|
||
|
||
const node_formula = this.vert_scrollView.content.getChildByName("node_formula")
|
||
if (node_formula.children.length > 0) {
|
||
node_formula.children.forEach(node => {
|
||
if (this.isTouchOnNode(node, touchPos)) {
|
||
// console.log('✅ 点中了节点:', node.name);
|
||
this.curSelectFormula = node
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
private _onTouchMove(event: EventTouch) {
|
||
|
||
// // console.log("_onTouchMove")
|
||
|
||
event.propagationStopped = false
|
||
|
||
|
||
if (!this._touchLastPos) {
|
||
console.warn("_onTouchMove, no _touchLastPos, return")
|
||
return;
|
||
}
|
||
|
||
const loc = event.getUILocation();
|
||
const deltaX = loc.x - this._touchLastPos.x;
|
||
const deltaY = loc.y - this._touchLastPos.y;
|
||
|
||
switch (this._curScrollType) {
|
||
case SCROLL_TYPE.NULL:
|
||
if (Math.abs(deltaX) > 0 || Math.abs(deltaY) > 0) {
|
||
|
||
this._touchLastPos = { x: loc.x, y: loc.y };
|
||
|
||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||
// console.log("横向滑动")
|
||
|
||
this._curScrollType = SCROLL_TYPE.HORIZONTAL
|
||
|
||
this.handleHorScroll(deltaX)
|
||
|
||
} else {
|
||
// console.log("纵向滑动")
|
||
|
||
this._curScrollType = SCROLL_TYPE.VERTICAL
|
||
|
||
this.handleVertScroll(deltaY)
|
||
}
|
||
|
||
} else {
|
||
// console.log("_onTouchMove, 滑动距离过小,取消判定")
|
||
}
|
||
break;
|
||
|
||
case SCROLL_TYPE.HORIZONTAL:
|
||
this._touchLastPos = { x: loc.x, y: loc.y };
|
||
this.handleHorScroll(deltaX)
|
||
|
||
|
||
break;
|
||
|
||
case SCROLL_TYPE.VERTICAL:
|
||
this._touchLastPos = { x: loc.x, y: loc.y };
|
||
this.handleVertScroll(deltaY)
|
||
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
private _onTouchEnd(event: EventTouch) {
|
||
|
||
// console.warn("_onTouchEnd")
|
||
|
||
const touchPos = event.getUILocation();
|
||
|
||
event.propagationStopped = false
|
||
|
||
const node_formula = this.vert_scrollView.content.getChildByName("node_formula")
|
||
if (!this.curSelectFormula && node_formula.children.length != 0) {
|
||
this.node_history_detail.emit("hide_history_formula_detail", this.vert_scrollView)
|
||
} else {
|
||
node_formula.children.forEach(node => {
|
||
if (this.isTouchOnNode(node, touchPos)) {
|
||
// console.log('✅ 点中了节点:', node.name);
|
||
|
||
if (this.curSelectFormula == node) {
|
||
this.node_history_detail.emit("show_history_formula_detail", node)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
this.curSelectFormula = null
|
||
|
||
/**水平滚动会判断offset, 停留在某一个Item上*/
|
||
if (this._curScrollType == SCROLL_TYPE.HORIZONTAL) {
|
||
|
||
const width = this.item_detail.getComponent(UITransform).width
|
||
|
||
const curOffset = this.hor_scrollView.getScrollOffset()
|
||
|
||
const curItemX = -this.page * width
|
||
|
||
|
||
const jugOffset = (width / 2) * 0.2
|
||
|
||
//
|
||
if (curOffset.x < curItemX - jugOffset) {
|
||
// console.log("滑过一半,跳到下一个")
|
||
this.page += 1
|
||
this.vert_scrollView = this.hor_scrollView.content.children[this.page].getComponent(ScrollView)
|
||
|
||
} else if (curOffset.x > curItemX + jugOffset) {
|
||
// console.log("滑过一半,跳到上一个")
|
||
this.page -= 1
|
||
this.vert_scrollView = this.hor_scrollView.content.children[this.page].getComponent(ScrollView)
|
||
} else {
|
||
// console.log("回弹回去")
|
||
}
|
||
|
||
this.showPage(this.page)
|
||
|
||
let vec = new Vec2(this.page / (this.hor_scrollView.content.children.length - 1), 0)
|
||
this.hor_scrollView.scrollTo(vec, 0.5)
|
||
this.checkPageBtn()
|
||
}
|
||
|
||
|
||
if (this._curScrollType != SCROLL_TYPE.NULL) {
|
||
this._touchLastPos = null
|
||
this._curScrollType = SCROLL_TYPE.NULL
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
handleHorScroll(deltaX) {
|
||
const curOffset = this.hor_scrollView.getScrollOffset()
|
||
|
||
if (deltaX > 0) {
|
||
// console.log("右滑")
|
||
|
||
this.hor_scrollView.scrollToOffset(new Vec2(-curOffset.x - deltaX, 0))
|
||
|
||
} else {
|
||
// console.log("左滑")
|
||
|
||
this.hor_scrollView.scrollToOffset(new Vec2(-curOffset.x - deltaX, 0))
|
||
}
|
||
}
|
||
|
||
handleVertScroll(deltaY) {
|
||
|
||
const curOffset = this.vert_scrollView.getScrollOffset()
|
||
if (deltaY > 0) {
|
||
// console.log("上滑")
|
||
|
||
this.vert_scrollView.scrollToOffset(new Vec2(0, curOffset.y + deltaY))
|
||
} else {
|
||
// console.log("下滑")
|
||
|
||
this.vert_scrollView.scrollToOffset(new Vec2(0, curOffset.y + deltaY))
|
||
}
|
||
}
|
||
|
||
checkPageBtn() {
|
||
this.flip.getChildByName("btn_page_left").active = this.page != 0
|
||
this.flip.getChildByName("btn_page_right").active = (this.page != this.hor_scrollView.content.children.length - 1)
|
||
|
||
this.node_history_detail.emit("remark_round_winning_list", this.page)
|
||
}
|
||
|
||
// 只显示左右相邻两页
|
||
showPage(page) {
|
||
this.hor_scrollView.content.children.forEach((vert, i) => {
|
||
if (Math.abs(i - page) <= 1) {
|
||
showAllChildren(vert)
|
||
} else {
|
||
hideAllChildren(vert)
|
||
}
|
||
})
|
||
}
|
||
|
||
jumpToPage(page: number) {
|
||
|
||
let maxIndex = this.hor_scrollView.content.children.length - 1
|
||
|
||
this.page = page
|
||
|
||
this.showPage(page)
|
||
|
||
this.vert_scrollView = this.hor_scrollView.content.children[this.page].getComponent(ScrollView)
|
||
let vec = new Vec2(this.page / maxIndex, 0)
|
||
this.hor_scrollView.scrollTo(vec)
|
||
|
||
this.checkPageBtn()
|
||
}
|
||
|
||
pageUp() {
|
||
|
||
let maxIndex = this.hor_scrollView.content.children.length - 1
|
||
this.page -= 1
|
||
|
||
this.showPage(this.page)
|
||
|
||
this.vert_scrollView = this.hor_scrollView.content.children[this.page].getComponent(ScrollView)
|
||
let vec = new Vec2(this.page / maxIndex, 0)
|
||
this.hor_scrollView.scrollTo(vec, 0.5)
|
||
|
||
this.checkPageBtn()
|
||
}
|
||
|
||
pageDown() {
|
||
|
||
let maxIndex = this.hor_scrollView.content.children.length - 1
|
||
this.page += 1
|
||
|
||
// console.log(`pageDown, ${this.page}`)
|
||
|
||
this.showPage(this.page)
|
||
|
||
this.vert_scrollView = this.hor_scrollView.content.children[this.page].getComponent(ScrollView)
|
||
let vec = new Vec2(this.page / maxIndex, 0)
|
||
this.hor_scrollView.scrollTo(vec, 0.5)
|
||
|
||
this.checkPageBtn()
|
||
}
|
||
|
||
onMouseWheel(event: EventMouse) {
|
||
|
||
// console.log("鼠标滚动")
|
||
|
||
// deltaY > 0:向下滚;deltaY < 0:向上滚
|
||
const delta = event.getScrollY() * this.scrollSpeed;
|
||
|
||
// 获取当前滚动位置
|
||
const offset = this.vert_scrollView.getScrollOffset();
|
||
|
||
let vec2 = offset.add2f(0, -delta)
|
||
// 更新纵向滚动
|
||
this.vert_scrollView.scrollToOffset(vec2, 0.1, true);
|
||
}
|
||
|
||
// 判断触摸点是否在节点矩形内
|
||
isTouchOnNode(node: Node, touchPos: Readonly<Vec2>): boolean {
|
||
const uiTransform = node.getComponent(UITransform);
|
||
if (!uiTransform) return false;
|
||
|
||
// 将世界坐标转换到本地坐标(判断矩形包围盒)
|
||
const rect = uiTransform.getBoundingBoxToWorld();
|
||
|
||
return rect.contains(touchPos);
|
||
}
|
||
|
||
}
|
||
|