diff --git a/android/titanium/src/java/org/appcelerator/titanium/TiC.java b/android/titanium/src/java/org/appcelerator/titanium/TiC.java index 040d9a003fd..1ea29cc5c36 100644 --- a/android/titanium/src/java/org/appcelerator/titanium/TiC.java +++ b/android/titanium/src/java/org/appcelerator/titanium/TiC.java @@ -159,6 +159,7 @@ public class TiC public static final String EVENT_RESUME = "resume"; public static final String EVENT_RESUMED = "resumed"; public static final String EVENT_RETURN = "return"; + public static final String EVENT_ROTATE = "rotate"; public static final String EVENT_ROWS_SELECTED = "rowsselected"; public static final String EVENT_SCROLL = "scroll"; public static final String EVENT_SCROLLEND = "scrollend"; diff --git a/android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java b/android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java index 73630f0c02a..658f82eda04 100644 --- a/android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java +++ b/android/titanium/src/java/org/appcelerator/titanium/view/TiUIView.java @@ -1806,6 +1806,22 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve int pointersDown = 0; int touchSlop; + private void doRotationEvent(MotionEvent event) + { + // Calculate the angle between the two fingers + float deltaX = event.getX(0) - event.getX(1); + float deltaY = event.getY(0) - event.getY(1); + double radians = Math.atan(deltaY / deltaX); + double degrees = Math.toDegrees(radians); + + if (event.getActionMasked() == MotionEvent.ACTION_MOVE) { + KrollDict data = new KrollDict(); + data.put(TiC.PROPERTY_ROTATE, degrees); + data.put(TiC.EVENT_PROPERTY_SOURCE, proxy); + fireEvent(TiC.EVENT_ROTATE, data); + } + } + @Override public boolean onTouch(View view, MotionEvent event) { @@ -1823,6 +1839,10 @@ public boolean onTouch(View view, MotionEvent event) lastUpEvent.put(TiC.EVENT_PROPERTY_OBSCURED, wasObscured(event)); } + if (proxy != null && proxy.hierarchyHasListener(TiC.EVENT_ROTATE) && event.getPointerCount() == 2) { + doRotationEvent(event); + } + // Do custom "longpress" event tracking. Store motion event data to be used by onLongClick() listener. // Note: Can't use GestureDetector for this since we would have to handle onDown() to make it work, // which would prevent view's onClick() and onLongClick() listeners from being called. diff --git a/apidoc/Titanium/UI/View.yml b/apidoc/Titanium/UI/View.yml index 2233fe4011e..ac7b525702b 100644 --- a/apidoc/Titanium/UI/View.yml +++ b/apidoc/Titanium/UI/View.yml @@ -471,6 +471,18 @@ events: may result in an endless loop. since: "2.0.0" + - name: rotate + summary: Fired when the device detects a two finger rotation. + description: | + This event is fired when doing a two finger rotation and returning the angle. + The event occurs continuously until a finger is lifted again. + platforms: [android, iphone, ipad, macos] + properties: + - name: rotate + summary: Rotation in degrees. + type: Number + since: "12.6.0" + - name: singletap summary: Fired when the device detects a single tap against the view. properties: diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.h b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.h index 4b6f10b05d1..33a54e82d3c 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.h +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.h @@ -82,6 +82,7 @@ void ModifyScrollViewForKeyboardHeightAndContentHeightWithResponderRect(UIScroll UITapGestureRecognizer *doubleTapRecognizer; UITapGestureRecognizer *twoFingerTapRecognizer; UIPinchGestureRecognizer *pinchRecognizer; + UIRotationGestureRecognizer *rotationRegognizer; UISwipeGestureRecognizer *leftSwipeRecognizer; UISwipeGestureRecognizer *rightSwipeRecognizer; UISwipeGestureRecognizer *upSwipeRecognizer; @@ -137,6 +138,7 @@ void ModifyScrollViewForKeyboardHeightAndContentHeightWithResponderRect(UIScroll @property (nonatomic, readonly) UITapGestureRecognizer *doubleTapRecognizer; @property (nonatomic, readonly) UITapGestureRecognizer *twoFingerTapRecognizer; @property (nonatomic, readonly) UIPinchGestureRecognizer *pinchRecognizer; +@property (nonatomic, readonly) UIRotationGestureRecognizer *rotationRegognizer; @property (nonatomic, readonly) UISwipeGestureRecognizer *leftSwipeRecognizer; @property (nonatomic, readonly) UISwipeGestureRecognizer *rightSwipeRecognizer; @property (nonatomic, readonly) UILongPressGestureRecognizer *longPressRecognizer; diff --git a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.m b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.m index 3f0331e6921..7077980604c 100644 --- a/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.m +++ b/iphone/TitaniumKit/TitaniumKit/Sources/API/TiUIView.m @@ -181,6 +181,7 @@ - (void)dealloc [doubleTapRecognizer release]; [twoFingerTapRecognizer release]; [pinchRecognizer release]; + [rotationRegognizer release]; [leftSwipeRecognizer release]; [rightSwipeRecognizer release]; [upSwipeRecognizer release]; @@ -241,6 +242,9 @@ - (void)ensureGestureListeners if ([(TiViewProxy *)proxy _hasListeners:@"pinch"]) { [[self gestureRecognizerForEvent:@"pinch"] setEnabled:YES]; } + if ([(TiViewProxy *)proxy _hasListeners:@"rotate"]) { + [[self gestureRecognizerForEvent:@"rotate"] setEnabled:YES]; + } if ([(TiViewProxy *)proxy _hasListeners:@"longpress"]) { [[self gestureRecognizerForEvent:@"longpress"] setEnabled:YES]; } @@ -253,6 +257,7 @@ - (BOOL)proxyHasGestureListeners [proxy _hasListeners:@"twofingertap"] || [proxy _hasListeners:@"swipe"] || [proxy _hasListeners:@"pinch"] || + [proxy _hasListeners:@"rotate"] || [proxy _hasListeners:@"longpress"]; } @@ -1362,6 +1367,17 @@ - (UIPinchGestureRecognizer *)pinchRecognizer return pinchRecognizer; } +- (UIRotationGestureRecognizer *)rotationRegognizer +{ + if (rotationRegognizer == nil) { + rotationRegognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(recognizedRotation:)]; + [self configureGestureRecognizer:rotationRegognizer]; + [self addGestureRecognizer:rotationRegognizer]; + } + rotationRegognizer.delegate = self; + return rotationRegognizer; +} + - (UISwipeGestureRecognizer *)leftSwipeRecognizer { if (leftSwipeRecognizer == nil) { @@ -1442,6 +1458,14 @@ - (void)recognizedTap:(UITapGestureRecognizer *)recognizer } } +- (void)recognizedRotation:(UIRotationGestureRecognizer *)recognizer +{ + NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys: + NUMDOUBLE(radiansToDegrees(recognizer.rotation)), @"rotate", + nil]; + [self.proxy fireEvent:@"rotate" withObject:event]; +} + - (void)recognizedPinch:(UIPinchGestureRecognizer *)recognizer { NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys: @@ -1690,6 +1714,9 @@ - (UIGestureRecognizer *)gestureRecognizerForEvent:(NSString *)event if ([event isEqualToString:@"pinch"]) { return [self pinchRecognizer]; } + if ([event isEqualToString:@"rotate"]) { + return [self rotationRegognizer]; + } if ([event isEqualToString:@"longpress"]) { return [self longPressRecognizer]; } @@ -1745,7 +1772,7 @@ - (void)sanitycheckListeners // TODO: This can be optimized and unwound later. { if (listenerArray == nil) { listenerArray = [[NSArray alloc] initWithObjects:@"singletap", - @"doubletap", @"twofingertap", @"swipe", @"pinch", @"longpress", nil]; + @"doubletap", @"twofingertap", @"swipe", @"rotate", @"pinch", @"longpress", nil]; } for (NSString *eventName in listenerArray) { if ([proxy _hasListeners:eventName]) {