# ScrollViewNesting **Repository Path**: lehung/scrollview-nesting ## Basic Information - **Project Name**: ScrollViewNesting - **Description**: ScrollView/PageView nested demo - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 19 - **Created**: 2022-10-27 - **Last Updated**: 2023-10-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README > ## ScrollView/PageView nesting scheme. > Based on CocosCreator2.4.x ## Recently, I have found a lot of friends in groups and forums who need ScrollView/PageView nesting, but Creator does not support it by default. We try to solve it. # 1. Analyze the reasons ___ If you look at the source code, you will find that every function that handles touch (ignoring the wheel) has these two lines at the beginning. ``` _onTouchBegan(event, captureListeners) { if (!this.enabledInHierarchy) return; if (this._hasNestedViewGroup(event, captureListeners)) return; ... } ``` The reason why nesting cannot be done lies in the _hasNestedViewGroup function ``` ... if (event.target.getComponent(cc.ViewGroup)) { return true; } ... ``` # 2. Solve the problem ___ At this time, most friends may inherit ScrollView or PageView, and then rewrite some methods to solve the nesting problem. But let's try a different angle here. For example, we manually emit a fake event so that it will not be filtered out by _hasNestedViewGroup, and our goal is to make it a separate component. ___ There is not much code, just upload the source code (freshly released, no bugs tested) Demo project address: https://gitee.com/cocos2d-zp/scrollview-nesting ``` const { ccclass, property } = cc._decorator; interface EventTouch extends cc.Event.EventTouch { simulate?: boolean sham?: boolean } @ccclass export default class ViewGroupNesting extends cc.Component { private events: EventTouch[] = []; onLoad() { this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchHandle, this, true); this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchHandle, this, true); this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchHandle, this, true); this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchHandle, this, true); } private onTouchHandle(event: EventTouch) { if (event.sham || event.simulate || event.target === this.node) return; const cancelEvent: EventTouch = new cc.Event.EventTouch(event.getTouches(), event.bubbles); cancelEvent.type = event.type; cancelEvent.touch = event.touch; cancelEvent.sham = true; // Question: Why not dispatchEvent directly here? // Answer: The ScrollView must consume the real event first, and then we can launch the fake one. // You can go to CCNode.js to find a _doDispatchEvent function, which uses a global variable like _cachedArray. // If the false is emitted first, the true data will be cleared. this.events.push(cancelEvent); } update() { if (this.events.length === 0) return; for (let index = 0; index < this.events.length; index++) { this.node.dispatchEvent(this.events[index]); } this.events.length = 0; } } ```