我智商爆棚
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

397 lines
13 KiB

4 weeks ago
import { LogUtils } from "../Util/LogUtils";
import FMItemLayout from "./FMItemLayout";
1./*
* @Descripttion: content节点
* @version: 1.0.0
* @Author: YeeChan
* @Date: 2020-07-17 16:52:59
*/
const { ccclass, property, requireComponent, disallowMultiple, menu, } = cc._decorator;
const EPSILON = 1e-4;
//滑动的方向
export enum SlideDirection {
HORIZONTAL = 1,//水平滚动
VERTICAL = 2//垂直滚动
}
export enum FMTouchEvent {
TouchStart = "touch_start",
Scrolling = "scrolling",
TouchEnded = "touch_ended"
}
@ccclass
@disallowMultiple() //防止多个相同类型(或子类型)的组件被添加到同一个节点
//@menu("FM组件/FMTouchMaskView")
export default class FMTouchMaskView extends cc.Component {
//layout预制体
@property({ tooltip: "layout预制体(0,1)", type: cc.Prefab })
public itemPrefab: cc.Prefab = null;
//滑动模式
@property()
protected _slideDirection: SlideDirection = SlideDirection.HORIZONTAL;
@property({ type: cc.Enum(SlideDirection), tooltip: "滚动方向:\n HORIZONTAL 水平滚动\nVERTICAL垂直滚动" })
set slideDirection(val: SlideDirection) {
this._slideDirection = val;
}
get slideDirection() { return this._slideDirection; }
//-----------------------------------
private _tempPoint_custom = cc.v2();
private _tempPrevPoint_custom = cc.v2();
private _outOfBoundaryAmount_custom = cc.v2(0, 0);
private _outOfBoundaryAmountDirty_custom = true;
//是否初始化过 标签
private _inited_custom: boolean = false;
//-------------------------
//是否移动
protected _touchMoved_custom = false;
//如果这个属性被设置为 true,那么滚动行为会取消子节点上注册的触摸事件,默认被设置为 true。* 注意,子节点上的 touchstart 事件仍然会触发,触点移动距离非常短的情况下 touchmove 和 touchend 也不会受影响。
protected cancelInnerEvents_custom = true;
//预制的宽高
protected itemPrefabWidth_custom: number = 0;
protected itemPrefabHeight_custom: number = 0;
//滚动区域
protected content_custom: cc.Node;
//预制体的脚本
private scriptItemPrefab_custom: FMItemLayout;
protected onLoad() {
this._init_custom();
}
/**
*
*/
protected _init_custom(): boolean {
if (this._inited_custom) {
//是否初始化过
return false;
}
let widget = this.node.getComponent(cc.Widget);
if (widget) {
widget.updateAlignment();
}
//遮罩
let view: cc.Node = new cc.Node();
view.anchorX = 0;
view.anchorY = 1;
let viewWidget = view.addComponent(cc.Widget);
viewWidget.top = 0;
viewWidget.left = 0;
viewWidget.right = 0;
viewWidget.bottom = 0;
viewWidget.isAlignTop = true;
viewWidget.isAlignLeft = true;
viewWidget.isAlignRight = true;
viewWidget.isAlignBottom = true;
this.node.addChild(view);
viewWidget.updateAlignment();
let mash = view.addComponent(cc.Mask);
mash.type = cc.Mask.Type.RECT;
//显示面板 滚动节点
this.content_custom = new cc.Node();
view.addChild(this.content_custom);
this.content_custom.width = view.width;
this.content_custom.height = view.height;
this.content_custom.anchorX = 0;
this.content_custom.anchorY = 1;
this.content_custom.x = 0;
this.content_custom.y = 0;
this.itemPrefabWidth_custom = this.itemPrefab.data.width;
this.itemPrefabHeight_custom = this.itemPrefab.data.height;
this.scriptItemPrefab_custom = this.itemPrefab.data.getComponent(FMItemLayout);
if (!this.scriptItemPrefab_custom) {
LogUtils.error_custom("FMTouchMaskView -> _init -> scriptItemPrefab is null");
} else {
if (this.scriptItemPrefab_custom.getItemChildrenCount_custom() == 0) {
LogUtils.error_custom("FMTouchMaskView -> _init -> scriptItemPrefab item child count ==0");
}
}
this._inited_custom = true;
return true;
}
protected _dispatchEvent_custom(name: FMTouchEvent) {
console.log("FMTouchMaskView -> _dispatchEvent -> name", name);
}
/**
* true true*
* touchstart touchmove touchend
* @param inner
*/
public setCancelInnerEvents_custom(inner: boolean) {
this.cancelInnerEvents_custom = inner;
}
/**
*
* @param touch
*/
protected handlePressLogic_custom(touch: cc.Touch) {
this._dispatchEvent_custom(FMTouchEvent.TouchStart);
}
/**
*
* @param touch
*/
protected handleMoveLogic_custom(touch: cc.Touch) {
let deltaMove = this.getLocalAxisAlignDelta_custom(touch);
deltaMove = this.clampDelta_custom(deltaMove);
let realMove = deltaMove;
let outOfBoundary = this.getHowMuchOutOfBoundary_custom(realMove);
realMove = realMove.add(outOfBoundary);
if (realMove.x !== 0 || realMove.y !== 0) {
this._moveContent_custom(realMove);
this._dispatchEvent_custom(FMTouchEvent.Scrolling);
}
}
/**
*
* @param touch
*/
protected handleReleaseLogic_custom(touch: cc.Touch) {
let delta = this.getLocalAxisAlignDelta_custom(touch);
this._dispatchEvent_custom(FMTouchEvent.TouchEnded);
}
private _flattenVectorByDirection_custom(vector) {
let result = vector;
result.x = this._slideDirection == SlideDirection.HORIZONTAL ? result.x : 0;
result.y = this._slideDirection == SlideDirection.VERTICAL ? result.y : 0;
return result;
}
private _moveContent_custom(deltaMove) {
let adjustedMove = this._flattenVectorByDirection_custom(deltaMove);
let newPosition = this.getContentPosition_custom().add(adjustedMove);
this.setContentPosition_custom(newPosition);
}
// Contains node angle calculations
private getLocalAxisAlignDelta_custom(touch): cc.Vec2 {
this.node.convertToNodeSpaceAR(touch.getLocation(), this._tempPoint_custom);
this.node.convertToNodeSpaceAR(touch.getPreviousLocation(), this._tempPrevPoint_custom);
return this._tempPoint_custom.sub(this._tempPrevPoint_custom);
}
//this is for nested scrollview
private _hasNestedViewGroup_custom(event: cc.Event.EventTouch, captureListeners) {
if (event.eventPhase !== cc.Event.CAPTURING_PHASE) return;
if (captureListeners) {
//captureListeners are arranged from child to parent
for (let i = 0; i < captureListeners.length; ++i) {
let item = captureListeners[i];
if (this.node === item) {
if (event.target.getComponent(cc.ViewGroup)) {
return true;
}
return false;
}
if (item.getComponent(cc.ViewGroup)) {
return true;
}
}
}
return false;
}
//This is for Scrollview as children of a Button
private _stopPropagationIfTargetIsMe_custom(event) {
if (event.eventPhase === cc.Event.AT_TARGET && event.target === this.node) {
event.stopPropagation();
}
}
// touch event handler
private _onTouchBegan_custom(event: cc.Event.EventTouch, captureListeners) {
if (!this.enabledInHierarchy) return;
if (this._hasNestedViewGroup_custom(event, captureListeners)) return;
let touch = event.touch;
if (this.content_custom) {
this.handlePressLogic_custom(touch);
}
this._touchMoved_custom = false;
this._stopPropagationIfTargetIsMe_custom(event);
}
private _onTouchMoved_custom(event: cc.Event.EventTouch, captureListeners) {
if (!this.enabledInHierarchy) return;
if (this._hasNestedViewGroup_custom(event, captureListeners)) return;
let touch = event.touch;
if (!this.node["_hitTest"](touch.getLocation(), this.node)) {//过滤掉不在区域内移动
return;
}
if (this.content_custom) {
this.handleMoveLogic_custom(touch);
}
// Do not prevent touch events in inner nodes
if (!this.cancelInnerEvents_custom) {
return;
}
let deltaMove = touch.getLocation().sub(touch.getStartLocation());
//FIXME: touch move delta should be calculated by DPI.
if (deltaMove.mag() > 7) {
if (!this._touchMoved_custom) {
// && event.target !== this.node
// Simulate touch cancel for target node
let 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_custom = true;
}
}
this._stopPropagationIfTargetIsMe_custom(event);
}
private _onTouchEnded_custom(event: cc.Event.EventTouch, captureListeners) {
if (!this.enabledInHierarchy) return;
if (this._hasNestedViewGroup_custom(event, captureListeners)) return;
let touch = event.touch;
if (this.content_custom) {
this.handleReleaseLogic_custom(touch);
}
if (this._touchMoved_custom) {
event.stopPropagation();
} else {
this._stopPropagationIfTargetIsMe_custom(event);
}
}
private _onTouchCancelled_custom(event, captureListeners) {
if (!this.enabledInHierarchy) return;
if (this._hasNestedViewGroup_custom(event, captureListeners)) return;
// Filte touch cancel event send from self
if (!event.simulate) {
let touch = event.touch;
if (this.content_custom) {
this.handleReleaseLogic_custom(touch);
}
}
this._stopPropagationIfTargetIsMe_custom(event);
}
private clampDelta_custom(delta) {
if (this._slideDirection == SlideDirection.HORIZONTAL) {
delta.y = 0;
} else if (this._slideDirection == SlideDirection.VERTICAL) {
delta.x = 0;
}
return delta;
}
private getHowMuchOutOfBoundary_custom(addition) {
addition = addition || cc.v2(0, 0);
if (addition.fuzzyEquals(cc.v2(0, 0), EPSILON) && !this._outOfBoundaryAmountDirty_custom) {
return this._outOfBoundaryAmount_custom;
}
let outOfBoundaryAmount = cc.v2(0, 0);
if (addition.fuzzyEquals(cc.v2(0, 0), EPSILON)) {
this._outOfBoundaryAmount_custom = outOfBoundaryAmount;
this._outOfBoundaryAmountDirty_custom = false;
}
outOfBoundaryAmount = this.clampDelta_custom(outOfBoundaryAmount);
return outOfBoundaryAmount;
}
private getContentPosition_custom() {
return this.content_custom.getPosition();
}
private setContentPosition_custom(position) {
if (position.fuzzyEquals(this.getContentPosition_custom(), EPSILON)) {
return;
}
this.content_custom.setPosition(position);
this._outOfBoundaryAmountDirty_custom = true;
}
onEnable() {
this._registerEvent_custom();
}
onDisable() {
this._unregisterEvent_custom();
}
//private methods
private _registerEvent_custom() {
this.node.on(cc.Node.EventType.TOUCH_START, this._onTouchBegan_custom, this, true);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved_custom, this, true);
this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnded_custom, this, true);
this.node.on(
cc.Node.EventType.TOUCH_CANCEL,
this._onTouchCancelled_custom,
this,
true
);
}
private _unregisterEvent_custom() {
this.node.off(
cc.Node.EventType.TOUCH_START,
this._onTouchBegan_custom,
this,
true
);
this.node.off(cc.Node.EventType.TOUCH_MOVE, this._onTouchMoved_custom, this, true);
this.node.off(cc.Node.EventType.TOUCH_END, this._onTouchEnded_custom, this, true);
this.node.off(
cc.Node.EventType.TOUCH_CANCEL,
this._onTouchCancelled_custom,
this,
true
);
}
}