rp_11001/assets/Game/scripts/game/ScrollControl.ts
2025-11-08 14:26:11 +08:00

338 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}