Files
NativeScript/ui/gestures/gestures.android.ts
2015-11-12 12:43:17 +02:00

392 lines
14 KiB
TypeScript

import common = require("./gestures-common");
import definition = require("ui/gestures");
import observable = require("data/observable");
import view = require("ui/core/view");
import trace = require("trace");
global.moduleMerge(common, exports);
var SWIPE_THRESHOLD = 100;
var SWIPE_VELOCITY_THRESHOLD = 100;
export class GesturesObserver extends common.GesturesObserver {
private _onTouchListener: android.view.View.OnTouchListener;
public _simpleGestureDetector: android.view.GestureDetector;
public _scaleGestureDetector: android.view.ScaleGestureDetector;
public _swipeGestureDetector: android.view.GestureDetector;
public _panGestureDetector: android.view.GestureDetector
private _onTargetLoaded: (data: observable.EventData) => void;
private _onTargetUnloaded: (data: observable.EventData) => void;
public observe(type: definition.GestureTypes) {
if (this.target) {
this.type = type;
this._onTargetLoaded = args => {
trace.write(this.target + ".target loaded. android:" + this.target._nativeView, "gestures");
this._attach(this.target, type);
};
this._onTargetUnloaded = args => {
trace.write(this.target + ".target unloaded. android:" + this.target._nativeView, "gestures");
this._detach();
};
this.target.on(view.View.loadedEvent, this._onTargetLoaded);
this.target.on(view.View.unloadedEvent, this._onTargetUnloaded);
if (this.target.isLoaded) {
this._attach(this.target, type);
}
}
}
public disconnect() {
this._detach();
if (this.target) {
this.target.off(view.View.loadedEvent, this._onTargetLoaded);
this.target.off(view.View.unloadedEvent, this._onTargetUnloaded);
this._onTargetLoaded = null;
this._onTargetUnloaded = null;
}
// clears target, context and callback references
super.disconnect();
}
private _detach() {
trace.write(this.target + "._detach() android:" + this.target._nativeView, "gestures");
this._onTouchListener = null;
this._simpleGestureDetector = null;
this._scaleGestureDetector = null;
this._swipeGestureDetector = null;
this._panGestureDetector = null;
}
private _attach(target: view.View, type: definition.GestureTypes) {
trace.write(this.target + "._attach() android:" + this.target._nativeView, "gestures");
this._detach();
if (type & definition.GestureTypes.tap || type & definition.GestureTypes.doubleTap || type & definition.GestureTypes.longPress) {
this._simpleGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new TapAndDoubleTapGestureListener(this, this.target, type));
}
if (type & definition.GestureTypes.pinch) {
this._scaleGestureDetector = new android.view.ScaleGestureDetector(target._context, new PinchGestureListener(this, this.target));
}
if (type & definition.GestureTypes.swipe) {
this._swipeGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new SwipeGestureListener(this, this.target));
}
if (type & definition.GestureTypes.pan) {
this._panGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new PanGestureListener(this, this.target));
}
}
public androidOnTouchEvent(motionEvent: android.view.MotionEvent) {
if (this._simpleGestureDetector) {
this._simpleGestureDetector.onTouchEvent(motionEvent);
}
if (this._scaleGestureDetector) {
this._scaleGestureDetector.onTouchEvent(motionEvent);
}
if (this._swipeGestureDetector) {
this._swipeGestureDetector.onTouchEvent(motionEvent);
}
if (this._panGestureDetector) {
this._panGestureDetector.onTouchEvent(motionEvent);
}
if (this.type & definition.GestureTypes.rotation && motionEvent.getPointerCount() === 2) {
var deltaX = motionEvent.getX(0) - motionEvent.getX(1);
var deltaY = motionEvent.getY(0) - motionEvent.getY(1);
var radians = Math.atan(deltaY / deltaX);
var degrees = radians * (180 / Math.PI);
var args = <definition.RotationGestureEventData>{
type: definition.GestureTypes.rotation,
view: this.target,
android: motionEvent,
rotation: degrees,
ios: undefined,
object: this.target,
eventName: definition.toString(definition.GestureTypes.rotation),
state: getState(motionEvent)
}
//var observer = that.get();
if (this.callback) {
this.callback.call(this.context, args);
}
}
}
}
function getState(e: android.view.MotionEvent) {
if (e.getAction() === android.view.MotionEvent.ACTION_DOWN) {
return common.GestureStateTypes.began;
} else if (e.getAction() === android.view.MotionEvent.ACTION_CANCEL) {
return common.GestureStateTypes.cancelled;
} else if (e.getAction() === android.view.MotionEvent.ACTION_MOVE) {
return common.GestureStateTypes.changed;
} else if (e.getAction() === android.view.MotionEvent.ACTION_UP) {
return common.GestureStateTypes.ended;
}
}
function _getArgs(type: definition.GestureTypes, view: view.View, e: android.view.MotionEvent): definition.GestureEventData {
return <definition.GestureEventData>{
type: type,
view: view,
android: e,
ios: undefined,
object: view,
eventName: definition.toString(type),
};
}
function _getSwipeArgs(direction: definition.SwipeDirection, view: view.View,
initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent): definition.SwipeGestureEventData {
return <definition.SwipeGestureEventData>{
type: definition.GestureTypes.swipe,
view: view,
android: { initial: initialEvent, current: currentEvent },
direction: direction,
ios: undefined,
object: view,
eventName: definition.toString(definition.GestureTypes.swipe),
state: getState(currentEvent)
};
}
function _getPanArgs(deltaX: number, deltaY: number, view: view.View,
initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent): definition.PanGestureEventData {
return <definition.PanGestureEventData>{
type: definition.GestureTypes.pan,
view: view,
android: { initial: initialEvent, current: currentEvent },
deltaX: deltaX,
deltaY: deltaY,
ios: undefined,
object: view,
eventName: definition.toString(definition.GestureTypes.pan),
state: getState(currentEvent)
};
}
function _executeCallback(observer: GesturesObserver, args: definition.GestureEventData) {
if (observer && observer.callback) {
observer.callback.call((<any>observer)._context, args);
}
}
class TapAndDoubleTapGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
private _observer: GesturesObserver;
private _target: view.View;
private _type: number;
constructor(observer: GesturesObserver, target: view.View, type: number) {
super();
this._observer = observer;
this._target = target;
this._type = type;
return global.__native(this);
}
public onSingleTapUp(motionEvent: android.view.MotionEvent): boolean {
if (this._type & definition.GestureTypes.tap) {
var args = _getArgs(definition.GestureTypes.tap, this._target, motionEvent);
_executeCallback(this._observer, args);
}
return true;
}
public onDoubleTap(motionEvent: android.view.MotionEvent): boolean {
if (this._type & definition.GestureTypes.doubleTap) {
var args = _getArgs(definition.GestureTypes.doubleTap, this._target, motionEvent);
_executeCallback(this._observer, args);
}
return true;
}
public onDown(motionEvent: android.view.MotionEvent): boolean {
return true;
}
public onLongPress(motionEvent: android.view.MotionEvent): void {
if (this._type & definition.GestureTypes.longPress) {
var args = _getArgs(definition.GestureTypes.longPress, this._target, motionEvent);
_executeCallback(this._observer, args);
}
}
}
class PinchGestureListener extends android.view.ScaleGestureDetector.SimpleOnScaleGestureListener {
private _observer: GesturesObserver;
private _target: view.View;
private _state: common.GestureStateTypes;
constructor(observer: GesturesObserver, target: view.View) {
super();
this._observer = observer;
this._target = target;
return global.__native(this);
}
public onScale(detector: android.view.ScaleGestureDetector): boolean {
var args = <definition.PinchGestureEventData>{
type: definition.GestureTypes.pinch,
view: this._target,
android: detector,
scale: detector.getScaleFactor(),
object: this._target,
eventName: definition.toString(definition.GestureTypes.pinch),
ios: undefined,
state: common.GestureStateTypes.changed
};
_executeCallback(this._observer, args);
return true;
}
public onScaleBegin(detector: android.view.ScaleGestureDetector): boolean {
var args = <definition.PinchGestureEventData>{
type: definition.GestureTypes.pinch,
view: this._target,
android: detector,
scale: detector.getScaleFactor(),
object: this._target,
eventName: definition.toString(definition.GestureTypes.pinch),
ios: undefined,
state: common.GestureStateTypes.began
};
_executeCallback(this._observer, args);
return true;
}
public onScaleEnd(detector: android.view.ScaleGestureDetector): void {
var args = <definition.PinchGestureEventData>{
type: definition.GestureTypes.pinch,
view: this._target,
android: detector,
scale: detector.getScaleFactor(),
object: this._target,
eventName: definition.toString(definition.GestureTypes.pinch),
ios: undefined,
state: common.GestureStateTypes.ended
};
_executeCallback(this._observer, args);
}
}
class SwipeGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
private _observer: GesturesObserver;
private _target: view.View;
constructor(observer: GesturesObserver, target: view.View) {
super();
this._observer = observer;
this._target = target;
return global.__native(this);
}
public onDown(motionEvent: android.view.MotionEvent): boolean {
return true;
}
public onFling(initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent, velocityX: number, velocityY: number): boolean {
var result = false;
var args: definition.SwipeGestureEventData;
try {
var deltaY = currentEvent.getY() - initialEvent.getY();
var deltaX = currentEvent.getX() - initialEvent.getX();
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (Math.abs(deltaX) > SWIPE_THRESHOLD
&& Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (deltaX > 0) {
args = _getSwipeArgs(definition.SwipeDirection.right, this._target, initialEvent, currentEvent);
_executeCallback(this._observer, args);
result = true;
} else {
args = _getSwipeArgs(definition.SwipeDirection.left, this._target, initialEvent, currentEvent);
_executeCallback(this._observer, args);
result = true;
}
}
} else {
if (Math.abs(deltaY) > SWIPE_THRESHOLD
&& Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (deltaY > 0) {
args = _getSwipeArgs(definition.SwipeDirection.down, this._target, initialEvent, currentEvent);
_executeCallback(this._observer, args);
result = true;
} else {
args = _getSwipeArgs(definition.SwipeDirection.up, this._target, initialEvent, currentEvent);
_executeCallback(this._observer, args);
result = true;
}
}
}
} catch (ex) {
//
}
return result;
}
}
class PanGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
private _observer: GesturesObserver;
private _target: view.View;
constructor(observer: GesturesObserver, target: view.View) {
super();
this._observer = observer;
this._target = target;
return global.__native(this);
}
public onDown(motionEvent: android.view.MotionEvent): boolean {
return false;
}
public onScroll(initialEvent: android.view.MotionEvent, currentEvent: android.view.MotionEvent, lastDeltaX: number, lastDeltaY: number): boolean {
var deltaX = currentEvent.getX() - initialEvent.getX();
var deltaY = currentEvent.getY() - initialEvent.getY();
var args = _getPanArgs(deltaX, deltaY, this._target, initialEvent, currentEvent);
_executeCallback(this._observer, args);
return true;
}
}