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*/ @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): boolean { const uiTransform = node.getComponent(UITransform); if (!uiTransform) return false; // 将世界坐标转换到本地坐标(判断矩形包围盒) const rect = uiTransform.getBoundingBoxToWorld(); return rect.contains(touchPos); } }