123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- import ScrollInner from "./ScrollInner";
- const { ccclass, property, menu } = cc._decorator;
- @ccclass
- @menu('Scroll/ScrollOut')
- export default class ScrollOut extends cc.ScrollView {
- @property(ScrollInner)
- scrollInnerViews: ScrollInner[] = []
- scrollInnerView: ScrollInner;
- canScroll: boolean = true
- isFirst: boolean = true;
- m_PlanDir: number;
- onLoad() {
- this.m_PlanDir = null;
- this.scrollInnerViews.forEach(inner => {
- inner.setOuterScrollView(this);
- });
- }
- //是否为子物体
- //注意,这里递归, 如果child藏的太深, 可能影响效率。其实也还好,只是开始滑动时执行一次。
- _isHisChild(child, undeterminedParent) {
- if (child == undeterminedParent) {
- return true;
- }
- if (child.parent != null) {
- if (child.parent == undeterminedParent) {
- return true;
- } else {
- return this._isHisChild(child.parent, undeterminedParent);
- }
- }
- return false;
- }
- //判断Target是否是InnerScrollView的子物体, 如果是,就返回这个InnerScrollView。
- //注意,这里遍历所有InnerScrollView, 如果InnerScrollView数量太多,可能影响效率。其实也还好,只是开始滑动时执行一次。
- _findScrollingInnerSv(target) {
- for (let i = 0; i < this.scrollInnerViews.length; i++) {
- let isHisChild = this._isHisChild(target, this.scrollInnerViews[i].node);
- if (isHisChild) {
- return this.scrollInnerViews[i];
- }
- }
- return null;
- }
- isSame() {
- return (this.horizontal && this.scrollInnerView.horizontal) || (this.vertical && this.scrollInnerView.vertical)
- }
- //#region 重写cc.ScrollView的方法
- _hasNestedViewGroup(event, captureListeners) {
- if (event.eventPhase !== cc.Event.CAPTURING_PHASE) return;
- //不阻止out上onTouch事件执行。
- return false;
- }
- _onTouchBegan(event, captureListeners) {
- if (!this.enabledInHierarchy) return;
- if (this._hasNestedViewGroup(event, captureListeners)) return;
- //重置计划方向
- this.m_PlanDir = null;
- this.scrollInnerView = null;
- this.isFirst = true
- var touch = event.touch;
- if (this.content) {
- this["_handlePressLogic"](touch);
- }
- this["_touchMoved"] = false;
- this["_stopPropagationIfTargetIsMe"](event);
- }
- _onTouchMoved(event, captureListeners) {
- // 答疑:为什么确定 scrollInnerView, 不用captureListeners, 而要用this._findScrollingInnerSv?
- // 因为,在子ScrollView上拖动时, captureListeners中并不包含该子ScrollView本身。
- // cc.log("----------------------------");
- // captureListeners.forEach((captureListener) => {
- // cc.log(captureListener.name);
- // });
- if (!this.enabledInHierarchy) return;
- if (this._hasNestedViewGroup(event, captureListeners)) return;
- var touch = event.touch;
- var deltaMove = touch.getLocation().sub(touch.getStartLocation());
- //在滑动时, 设置开始时滑动的方向为计划方向
- //为什么在Outer中做这件事?
- //因为Outer的_onTouchMoved比Inner的早执行, 如果在Inner里做, Outer中就得忽略一帧,体验可能会不好。
- if (deltaMove.mag() > 7) {
- this.scrollInnerView = this._findScrollingInnerSv(event.target);
- if (this.scrollInnerView != null) {
- let contentSize = this.scrollInnerView.content.getContentSize();
- let scrollViewSize = this.scrollInnerView.node.getContentSize();
- if ((this.scrollInnerView.vertical && (contentSize.height > scrollViewSize.height)) || (this.scrollInnerView.horizontal && (contentSize.width > scrollViewSize.width))) {
- if (this.m_PlanDir == null) {
- this.m_PlanDir = Math.abs(deltaMove.x) > Math.abs(deltaMove.y) ? 1 : -1; //1水平 -1垂直
- }
- if (this.m_PlanDir == 1) {
- if (this.isSame()) {
- if (this.isFirst) {
- this.isFirst = false
- //回滚0.1 否则走不下去
- if (this.scrollInnerView.getScrollOffset().x >= 0) {
- this.scrollInnerView.content.x = -0.1
- return
- }
- if (this.scrollInnerView.getScrollOffset().x <= -this.scrollInnerView.getMaxScrollOffset().x) {
- this.scrollInnerView.content.x = -this.scrollInnerView.getMaxScrollOffset().x + 0.1
- return
- }
- }
- this.canScroll = this.horizontal && (this.scrollInnerView.getScrollOffset().x >= 0 || this.scrollInnerView.getScrollOffset().x <= -this.scrollInnerView.getMaxScrollOffset().x)
- this.scrollInnerView.canScroll = !this.canScroll
- } else {
- this.canScroll = this.horizontal
- this.scrollInnerView.canScroll = this.scrollInnerView.horizontal
- }
- } else {
- if (this.isSame()) {
- if (this.isFirst) {
- this.isFirst = false
- //回滚0.1 否则走不下去
- if (this.scrollInnerView.getScrollOffset().y <= 0) {
- this.scrollInnerView.content.y = 0.1
- return
- }
- if (this.scrollInnerView.getScrollOffset().y >= this.scrollInnerView.getMaxScrollOffset().y) {
- this.scrollInnerView.content.y = this.scrollInnerView.getMaxScrollOffset().y - 0.1
- return
- }
- }
- this.canScroll = this.vertical && this.scrollInnerView.getScrollOffset().y <= 0 || this.scrollInnerView.getScrollOffset().y >= this.scrollInnerView.getMaxScrollOffset().y
- this.scrollInnerView.canScroll = !this.canScroll
- } else {
- this.canScroll = this.vertical
- this.scrollInnerView.canScroll = this.scrollInnerView.vertical
- }
- }
- } else {
- this.canScroll = true;
- this.scrollInnerView.canScroll = false
- }
- } else {
- this.canScroll = true;
- }
- }
- if (this.content) {
- if (this.canScroll) {
- this["_handleMoveLogic"](touch);
- }
- }
- if (!this.cancelInnerEvents) {
- return;
- }
- //只取消会捕获事件的直接子物体(如Button)上的事件
- if (this.scrollInnerView == null) {
- if (deltaMove.mag() > 7) {
- if (!this["_touchMoved"] && event.target !== this.node) {
- var cancelEvent = new cc.Event.EventTouch(event.getTouches(), event.bubbles);
- cancelEvent.type = cc.Node.EventType.TOUCH_CANCEL;
- cancelEvent.touch = event.touch;
- cancelEvent["simulate"] = true;
- event.target.dispatchEvent(cancelEvent);
- this["_touchMoved"] = true;
- }
- }
- this["_stopPropagationIfTargetIsMe"](event);
- }
- }
- _onTouchEnded(event, captureListeners) {
- if (!this.enabledInHierarchy) return;
- if (this._hasNestedViewGroup(event, captureListeners)) return;
- this["_dispatchEvent"]('touch-up');
- let touch = event.touch;
- if (this.content) {
- this["_handleReleaseLogic"](touch);
- }
- if (this["_touchMoved"]) {
- event.stopPropagation();
- } else {
- this["_stopPropagationIfTargetIsMe"](event);
- }
- }
- _onTouchCancelled(event, captureListeners) {
- if (!this.enabledInHierarchy) return;
- if (this._hasNestedViewGroup(event, captureListeners)) return;
- // Filte touch cancel event send from self
- if (!event.simulate) {
- let touch = event.touch;
- if (this.content) {
- this["_handleReleaseLogic"](touch);
- }
- }
- this["_stopPropagationIfTargetIsMe"](event);
- }
- //#endregion
- }
|