react-native-gesture-handler
Version:
Experimental implementation of a new declarative API for gesture handling in react-native
173 lines (135 loc) • 4.5 kB
text/typescript
import { State } from '../../State';
import { Direction } from '../constants';
import { AdaptedEvent, Config } from '../interfaces';
import GestureHandler from './GestureHandler';
const DEFAULT_MAX_DURATION_MS = 800;
const DEFAULT_MIN_ACCEPTABLE_DELTA = 160;
const DEFAULT_DIRECTION = Direction.RIGHT;
const DEFAULT_NUMBER_OF_TOUCHES_REQUIRED = 1;
export default class FlingGestureHandler extends GestureHandler {
private numberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED;
private direction = DEFAULT_DIRECTION;
private maxDurationMs = DEFAULT_MAX_DURATION_MS;
private minAcceptableDelta = DEFAULT_MIN_ACCEPTABLE_DELTA;
private delayTimeout!: number;
private startX = 0;
private startY = 0;
private maxNumberOfPointersSimultaneously = 0;
private keyPointer = NaN;
public init(ref: number, propsRef: React.RefObject<unknown>): void {
super.init(ref, propsRef);
}
public updateGestureConfig({ enabled = true, ...props }: Config): void {
super.updateGestureConfig({ enabled: enabled, ...props });
if (this.config.direction) {
this.direction = this.config.direction;
}
if (this.config.numberOfPointers) {
this.numberOfPointersRequired = this.config.numberOfPointers;
}
}
protected transformNativeEvent() {
const rect: DOMRect = this.view.getBoundingClientRect();
return {
x: this.tracker.getLastAvgX() - rect.left,
y: this.tracker.getLastAvgY() - rect.top,
absoluteX: this.tracker.getLastAvgX(),
absoluteY: this.tracker.getLastAvgY(),
};
}
private startFling(): void {
this.startX = this.tracker.getLastX(this.keyPointer);
this.startY = this.tracker.getLastY(this.keyPointer);
this.begin();
this.maxNumberOfPointersSimultaneously = 1;
this.delayTimeout = setTimeout(() => this.fail(), this.maxDurationMs);
}
private tryEndFling(): boolean {
if (
this.maxNumberOfPointersSimultaneously ===
this.numberOfPointersRequired &&
((this.direction & Direction.RIGHT &&
this.tracker.getLastX(this.keyPointer) - this.startX >
this.minAcceptableDelta) ||
(this.direction & Direction.LEFT &&
this.startX - this.tracker.getLastX(this.keyPointer) >
this.minAcceptableDelta) ||
(this.direction & Direction.UP &&
this.startY - this.tracker.getLastY(this.keyPointer) >
this.minAcceptableDelta) ||
(this.direction & Direction.DOWN &&
this.tracker.getLastY(this.keyPointer) - this.startY >
this.minAcceptableDelta))
) {
clearTimeout(this.delayTimeout);
this.activate();
return true;
}
return false;
}
private endFling() {
if (!this.tryEndFling()) {
this.fail();
}
}
protected onPointerDown(event: AdaptedEvent): void {
this.tracker.addToTracker(event);
this.keyPointer = event.pointerId;
super.onPointerDown(event);
this.newPointerAction();
}
protected onPointerAdd(event: AdaptedEvent): void {
this.tracker.addToTracker(event);
super.onPointerAdd(event);
this.newPointerAction();
}
private newPointerAction(): void {
if (this.currentState === State.UNDETERMINED) {
this.startFling();
}
if (this.currentState !== State.BEGAN) {
return;
}
this.tryEndFling();
if (
this.tracker.getTrackedPointersCount() >
this.maxNumberOfPointersSimultaneously
) {
this.maxNumberOfPointersSimultaneously =
this.tracker.getTrackedPointersCount();
}
}
protected onPointerMove(event: AdaptedEvent): void {
this.tracker.track(event);
if (this.currentState !== State.BEGAN) {
return;
}
this.tryEndFling();
super.onPointerMove(event);
}
protected onPointerUp(event: AdaptedEvent): void {
super.onPointerUp(event);
this.onUp(event);
this.keyPointer = NaN;
}
protected onPointerRemove(event: AdaptedEvent): void {
super.onPointerRemove(event);
this.onUp(event);
}
private onUp(event: AdaptedEvent): void {
this.tracker.removeFromTracker(event.pointerId);
if (this.currentState !== State.BEGAN) {
return;
}
this.endFling();
}
public activate(force?: boolean): void {
super.activate(force);
this.end();
}
protected resetConfig(): void {
super.resetConfig();
this.numberOfPointersRequired = DEFAULT_NUMBER_OF_TOUCHES_REQUIRED;
this.direction = DEFAULT_DIRECTION;
}
}