Refactored gestures to support more scenarios in android.

This commit is contained in:
Nedyalko Nikolov
2015-05-26 10:25:42 +03:00
parent 0cb70233f0
commit f838f11844
9 changed files with 144 additions and 73 deletions

View File

@ -1,5 +1,22 @@
import frame = require("ui/frame"); import frame = require("ui/frame");
import pageModule = require("ui/page");
import textViewModule = require("ui/text-view");
export function buttonTap(args) { export function buttonTap(args) {
frame.topmost().goBack(); console.log("tap");
}
export function doubleTap(args) {
console.log("doubleTap");
}
export function checkRecognizers(args) {
var testTextView = <textViewModule.TextView>(page.getViewById("testTextView"));
console.log("testTextView: " + testTextView.ios.gestureRecognizers);
}
var page: pageModule.Page;
export function pageLoaded(args) {
page = <pageModule.Page>args.object;
} }

View File

@ -1,3 +1,6 @@
<Page xmlns="http://www.nativescript.org/tns.xsd"> <Page xmlns="http://www.nativescript.org/tns.xsd" loaded="pageLoaded">
<Button text="Back" tap="buttonTap"/> <StackLayout>
<TextView text="TEST FOR GESTURES" id="testTextView" style="font-size: 50" tap="buttonTap" doubleTap="doubleTap"/>
<Button text="CLICK" tap="checkRecognizers" />
</StackLayout>
</Page> </Page>

View File

@ -18,6 +18,7 @@ import listViewModule = require("ui/list-view");
import helper = require("../ui/helper"); import helper = require("../ui/helper");
import viewModule = require("ui/core/view"); import viewModule = require("ui/core/view");
import platform = require("platform"); import platform = require("platform");
import gesturesModule = require("ui/gestures");
export function test_load_IsDefined() { export function test_load_IsDefined() {
TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!"); TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!");
@ -186,7 +187,7 @@ export function test_parse_ShouldParseBindingsToGestures() {
p.bindingContext = context; p.bindingContext = context;
var lbl = <labelModule.Label>p.content; var lbl = <labelModule.Label>p.content;
var observer = (<any>lbl)._gesturesObserver; var observer = (<any>lbl)._gestureObservers[gesturesModule.GestureTypes.tap][0];
TKUnit.assert(observer !== undefined, "Expected result: true."); TKUnit.assert(observer !== undefined, "Expected result: true.");
TKUnit.assert(observer._context === context, "Context should be equal to binding context. Actual result: " + observer._context); TKUnit.assert(observer._context === context, "Context should be equal to binding context. Actual result: " + observer._context);

View File

@ -132,7 +132,7 @@ export class View extends proxy.ProxyObject implements definition.View {
public _cssClasses: Array<string> = []; public _cssClasses: Array<string> = [];
private _gesturesObserver: gestures.GesturesObserver; public _gestureObservers = {};
private _updatingInheritedProperties: boolean; private _updatingInheritedProperties: boolean;
public _options: definition.Options; public _options: definition.Options;
@ -147,9 +147,22 @@ export class View extends proxy.ProxyObject implements definition.View {
this._visualState = visualStateConstants.Normal; this._visualState = visualStateConstants.Normal;
} }
observe(type: number, callback: (args: gestures.GestureEventData) => void, thisArg?: any): gestures.GesturesObserver { observe(type: number, callback: (args: gestures.GestureEventData) => void, thisArg?: any): void {
this._gesturesObserver = gestures.observe(this, type, callback, thisArg); var gesturesList = this._getGesturesList(type, true);
return this._gesturesObserver; gesturesList.push(gestures.observe(this, type, callback, thisArg));
}
private _getGesturesList(gestureType: number, createIfNeeded): Array<gestures.GesturesObserver> {
if (!gestureType) {
throw new Error("GestureType must be a valid gesture!");
}
var list = this._gestureObservers[gestureType];
if (!list && createIfNeeded) {
list = [];
this._gestureObservers[gestureType] = list;
}
return list;
} }
getViewById<T extends View>(id: string): T { getViewById<T extends View>(id: string): T {

View File

@ -4,6 +4,7 @@ import trace = require("trace");
import utils = require("utils/utils"); import utils = require("utils/utils");
import dependencyObservable = require("ui/core/dependency-observable"); import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy"); import proxy = require("ui/core/proxy");
import gestures = require("ui/gestures");
// merge the exports of the common file with the exports of this file // merge the exports of the common file with the exports of this file
declare var exports; declare var exports;
@ -77,6 +78,81 @@ export class View extends viewCommon.View {
this._updateOnTouchListener(this.isUserInteractionEnabled); this._updateOnTouchListener(this.isUserInteractionEnabled);
} }
public onLoaded() {
super.onLoaded();
this.setOnTouchListener();
}
public onUnloaded() {
super.onUnloaded();
if (this.android && this.android.setOnTouchListener) {
this.android.setOnTouchListener(null);
}
}
private setOnTouchListener() {
if (this.android && this.android.setOnTouchListener && Object.keys(this._gestureObservers).length > 0) {
var that = new WeakRef(this);
if (this.android.setClickable) {
this.android.setClickable(true);
}
this.android.setOnTouchListener(new android.view.View.OnTouchListener({
onTouch: function (view: android.view.View, motionEvent: android.view.MotionEvent) {
var owner = that.get();
if (!owner) {
return false;
}
var i;
for (var prop in owner._gestureObservers) {
if (owner._gestureObservers.hasOwnProperty(prop)) {
for (i = 0; i < owner._gestureObservers[prop].length; i++) {
var gestureObserver = owner._gestureObservers[prop][i];
if (gestureObserver._simpleGestureDetector) {
gestureObserver._simpleGestureDetector.onTouchEvent(motionEvent);
}
if (gestureObserver._scaleGestureDetector) {
gestureObserver._scaleGestureDetector.onTouchEvent(motionEvent);
}
if (gestureObserver._swipeGestureDetector) {
gestureObserver._swipeGestureDetector.onTouchEvent(motionEvent);
}
if (gestureObserver._panGestureDetector) {
gestureObserver._panGestureDetector.onTouchEvent(motionEvent);
}
if (gestureObserver.type & gestures.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 = <gestures.RotationGestureEventData>{
type: gestures.GestureTypes.rotation,
view: owner,
android: motionEvent,
rotation: degrees,
ios: null
}
//var observer = that.get();
if (gestureObserver.callback) {
gestureObserver.callback.call(gestureObserver._context, args);
}
}
}
}
}
return owner.android.onTouchEvent(motionEvent);
}
}));
}
}
public _addViewCore(view: viewCommon.View) { public _addViewCore(view: viewCommon.View) {
if (this._context) { if (this._context) {
view._onAttached(this._context); view._onAttached(this._context);

2
ui/core/view.d.ts vendored
View File

@ -355,7 +355,7 @@ declare module "ui/core/view" {
*/ */
public focus(): boolean; public focus(): boolean;
observe(type: number, callback: (args: gestures.GestureEventData) => void, thisArg?: any): gestures.GesturesObserver; observe(type: number, callback: (args: gestures.GestureEventData) => void, thisArg?: any);
/** /**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method). * A basic method signature to hook an event listener (shortcut alias to the addEventListener method).

View File

@ -24,6 +24,7 @@ export class GesturesObserver implements definition.GesturesObserver {
private _onTargetLoaded: (data: observable.EventData) => void; private _onTargetLoaded: (data: observable.EventData) => void;
private _onTargetUnloaded: (data: observable.EventData) => void; private _onTargetUnloaded: (data: observable.EventData) => void;
public type: definition.GestureTypes;
constructor(callback: (args: definition.GestureEventData) => void) { constructor(callback: (args: definition.GestureEventData) => void) {
this._callback = callback; this._callback = callback;
@ -35,6 +36,7 @@ export class GesturesObserver implements definition.GesturesObserver {
public observe(target: view.View, type: definition.GestureTypes, thisArg?: any) { public observe(target: view.View, type: definition.GestureTypes, thisArg?: any) {
if (target) { if (target) {
this.type = type;
this._target = target; this._target = target;
this._context = thisArg; this._context = thisArg;
this._onTargetLoaded = args => { this._onTargetLoaded = args => {
@ -70,9 +72,6 @@ export class GesturesObserver implements definition.GesturesObserver {
private _dettach() { private _dettach() {
trace.write(this._target + "._detach() android:" + this._target.android, "gestures"); trace.write(this._target + "._detach() android:" + this._target.android, "gestures");
if (this._target && this._target.android) {
this._target.android.setOnTouchListener(null);
}
this._onTouchListener = null; this._onTouchListener = null;
this._simpleGestureDetector = null; this._simpleGestureDetector = null;
@ -86,7 +85,7 @@ export class GesturesObserver implements definition.GesturesObserver {
this._dettach(); this._dettach();
if (type & definition.GestureTypes.tap || type & definition.GestureTypes.doubleTap || type & definition.GestureTypes.longPress) { 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)); this._simpleGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new TapAndDoubleTapGestureListener(this, this._target, type));
} }
if (type & definition.GestureTypes.pinch) { if (type & definition.GestureTypes.pinch) {
@ -100,58 +99,6 @@ export class GesturesObserver implements definition.GesturesObserver {
if (type & definition.GestureTypes.pan) { if (type & definition.GestureTypes.pan) {
this._panGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new PanGestureListener(this, this._target)); this._panGestureDetector = new android.support.v4.view.GestureDetectorCompat(target._context, new PanGestureListener(this, this._target));
} }
var that = new WeakRef(this);
this._onTouchListener = new android.view.View.OnTouchListener({
onTouch: function (view: android.view.View, motionEvent: android.view.MotionEvent) {
var owner = that.get();
if (!owner) {
return false;
}
if (owner._simpleGestureDetector) {
owner._simpleGestureDetector.onTouchEvent(motionEvent);
}
if (owner._scaleGestureDetector) {
owner._scaleGestureDetector.onTouchEvent(motionEvent);
}
if (owner._swipeGestureDetector) {
owner._swipeGestureDetector.onTouchEvent(motionEvent);
}
if (owner._panGestureDetector) {
owner._panGestureDetector.onTouchEvent(motionEvent);
}
if (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: owner._target,
android: motionEvent,
rotation: degrees,
}
var observer = that.get();
if (observer && observer.callback) {
observer.callback.call(observer._context, args);
}
}
return true;
}
});
target.android.setOnTouchListener(this._onTouchListener);
} }
} }
@ -193,24 +140,30 @@ function _executeCallback(observer: GesturesObserver, args: definition.GestureEv
class TapAndDoubleTapGestureListener extends android.view.GestureDetector.SimpleOnGestureListener { class TapAndDoubleTapGestureListener extends android.view.GestureDetector.SimpleOnGestureListener {
private _observer: GesturesObserver; private _observer: GesturesObserver;
private _target: view.View; private _target: view.View;
private _type: number;
constructor(observer: GesturesObserver, target: view.View) { constructor(observer: GesturesObserver, target: view.View, type: number) {
super(); super();
this._observer = observer; this._observer = observer;
this._target = target; this._target = target;
this._type = type;
return global.__native(this); return global.__native(this);
} }
public onSingleTapConfirmed(motionEvent: android.view.MotionEvent): boolean { public onSingleTapConfirmed(motionEvent: android.view.MotionEvent): boolean {
var args = _getArgs(definition.GestureTypes.tap, this._target, motionEvent); if (this._type === definition.GestureTypes.tap) {
_executeCallback(this._observer, args); var args = _getArgs(definition.GestureTypes.tap, this._target, motionEvent);
_executeCallback(this._observer, args);
}
return true; return true;
} }
public onDoubleTap(motionEvent: android.view.MotionEvent): boolean { public onDoubleTap(motionEvent: android.view.MotionEvent): boolean {
var args = _getArgs(definition.GestureTypes.doubleTap, this._target, motionEvent); if (this._type === definition.GestureTypes.doubleTap) {
_executeCallback(this._observer, args); var args = _getArgs(definition.GestureTypes.doubleTap, this._target, motionEvent);
_executeCallback(this._observer, args);
}
return true; return true;
} }
@ -219,8 +172,10 @@ class TapAndDoubleTapGestureListener extends android.view.GestureDetector.Simple
} }
public onLongPress(motionEvent: android.view.MotionEvent): boolean { public onLongPress(motionEvent: android.view.MotionEvent): boolean {
var args = _getArgs(definition.GestureTypes.longPress, this._target, motionEvent); if (this._type === definition.GestureTypes.longPress) {
_executeCallback(this._observer, args); var args = _getArgs(definition.GestureTypes.longPress, this._target, motionEvent);
_executeCallback(this._observer, args);
}
return true; return true;
} }
} }

View File

@ -132,6 +132,11 @@ declare module "ui/gestures" {
* Disconnects the gesture observer. * Disconnects the gesture observer.
*/ */
disconnect(); disconnect();
/**
* Gesture type attached to the observer.
*/
type: GestureTypes;
} }
/** /**

View File

@ -58,6 +58,7 @@ class UIGestureRecognizerImpl extends NSObject {
export class GesturesObserver implements definition.GesturesObserver { export class GesturesObserver implements definition.GesturesObserver {
public _callback: (args: definition.GestureEventData) => void; public _callback: (args: definition.GestureEventData) => void;
public _target: view.View; public _target: view.View;
public type: definition.GestureTypes;
private _recognizers: {}; private _recognizers: {};
private _context: any; private _context: any;
@ -71,6 +72,7 @@ export class GesturesObserver implements definition.GesturesObserver {
public observe(target: view.View, type: definition.GestureTypes, thisArg?: any) { public observe(target: view.View, type: definition.GestureTypes, thisArg?: any) {
if (target) { if (target) {
this.type = type;
this._target = target; this._target = target;
this._context = thisArg; this._context = thisArg;
this._onTargetLoaded = args => { this._onTargetLoaded = args => {
@ -89,7 +91,6 @@ export class GesturesObserver implements definition.GesturesObserver {
this._attach(target, type); this._attach(target, type);
} }
} }
} }
private _attach(target: view.View, type: definition.GestureTypes) { private _attach(target: view.View, type: definition.GestureTypes) {