From 777fab828f787dfd6f40c3efecd90c9604315429 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 16 Jul 2021 12:45:42 +0200 Subject: [PATCH] Add duration to long press event (#1505) Description Added duration property to the LongPressGestureHandler events. This change allows checking how long the entire event lasted. Test code ```js import React, { Component } from 'react'; import { StyleSheet, View } from 'react-native'; import { LongPressGestureHandler, LongPressGestureHandlerStateChangeEvent, } from 'react-native-gesture-handler'; export class PressBox extends Component { private onHandlerStateChange = ( event: LongPressGestureHandlerStateChangeEvent ) => { console.log(`Duration: ${event.nativeEvent.duration}`); }; render() { return ( ); } } export default class Example extends Component { render() { return ( ); } } const styles = StyleSheet.create({ box: { width: 150, height: 150, alignSelf: 'center', backgroundColor: 'plum', margin: 10, zIndex: 200, }, }); ``` --- .../LongPressGestureHandler.java | 19 ++++++++++ .../react/RNGestureHandlerModule.java | 2 + .../docs/api/gesture-handlers/longpress-gh.md | 3 ++ examples/Example/src/multitap/index.tsx | 38 +++++++++++++++---- ios/Handlers/RNLongPressHandler.m | 35 ++++++++++++++++- ios/RNGestureHandlerEvents.h | 4 ++ ios/RNGestureHandlerEvents.m | 16 ++++++++ src/handlers/gestureHandlers.ts | 1 + 8 files changed, 109 insertions(+), 9 deletions(-) diff --git a/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java b/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java index 0eedccfea..1ee97700d 100644 --- a/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java +++ b/android/lib/src/main/java/com/swmansion/gesturehandler/LongPressGestureHandler.java @@ -2,6 +2,7 @@ import android.content.Context; import android.os.Handler; +import android.os.SystemClock; import android.view.MotionEvent; public class LongPressGestureHandler extends GestureHandler { @@ -13,6 +14,7 @@ public class LongPressGestureHandler extends GestureHandler void; +} + +interface ExampleState { + longPressDuration: number; +} +export class PressBox extends Component { private doubleTapRef = React.createRef(); private onHandlerStateChange = ( event: LongPressGestureHandlerStateChangeEvent ) => { - if (event.nativeEvent.state === State.ACTIVE) { - Alert.alert("I'm being pressed for so long"); - } + this.props.setDuration(event.nativeEvent.duration); }; private onSingleTap = (event: TapGestureHandlerStateChangeEvent) => { if (event.nativeEvent.state === State.ACTIVE) { @@ -51,12 +56,28 @@ export class PressBox extends Component { } } -export default class Example extends Component { +export default class Example extends Component< + Record, + ExampleState +> { + constructor(props: Record) { + super(props); + + this.state = { longPressDuration: 0 }; + } + render() { return ( - + + Duration of the last long press: {this.state.longPressDuration}ms + + + this.setState({ longPressDuration: duration }) + } + /> ); @@ -75,4 +96,7 @@ const styles = StyleSheet.create({ margin: 10, zIndex: 200, }, + text: { + marginLeft: 20, + }, }); diff --git a/ios/Handlers/RNLongPressHandler.m b/ios/Handlers/RNLongPressHandler.m index fa4ef4cbd..c79addf16 100644 --- a/ios/Handlers/RNLongPressHandler.m +++ b/ios/Handlers/RNLongPressHandler.m @@ -12,9 +12,16 @@ #import -@interface RNBetterLongPressGestureRecognizer : UILongPressGestureRecognizer +#import + +@interface RNBetterLongPressGestureRecognizer : UILongPressGestureRecognizer { + uint64_t startTime; + uint64_t previousTime; +} - (id)initWithGestureHandler:(RNGestureHandler*)gestureHandler; +- (void)handleGesture:(UIGestureRecognizer *)recognizer; +- (NSUInteger) getDuration; @end @@ -24,12 +31,22 @@ @implementation RNBetterLongPressGestureRecognizer { - (id)initWithGestureHandler:(RNGestureHandler*)gestureHandler { - if ((self = [super initWithTarget:gestureHandler action:@selector(handleGesture:)])) { + if ((self = [super initWithTarget:self action:@selector(handleGesture:)])) { _gestureHandler = gestureHandler; } return self; } +- (void)handleGesture:(UIGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateBegan) { + startTime = mach_absolute_time(); + } + previousTime = mach_absolute_time(); + + [_gestureHandler handleGesture:recognizer]; +} + - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; @@ -39,6 +56,11 @@ - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event } } +- (NSUInteger)getDuration +{ + return (NSUInteger)(((previousTime - startTime) / 1000000 + self.minimumPressDuration * 1000)); +} + @end @@ -88,5 +110,14 @@ - (RNGestureHandlerState)state } return [super state]; } + +- (RNGestureHandlerEventExtraData *)eventExtraData:(UIGestureRecognizer *)recognizer +{ + return [RNGestureHandlerEventExtraData + forPosition:[recognizer locationInView:recognizer.view] + withAbsolutePosition:[recognizer locationInView:recognizer.view.window] + withNumberOfTouches:recognizer.numberOfTouches + withDuration:[(RNBetterLongPressGestureRecognizer*)recognizer getDuration]]; +} @end diff --git a/ios/RNGestureHandlerEvents.h b/ios/RNGestureHandlerEvents.h index 85f162062..2fc6b5fdb 100644 --- a/ios/RNGestureHandlerEvents.h +++ b/ios/RNGestureHandlerEvents.h @@ -14,6 +14,10 @@ + (RNGestureHandlerEventExtraData *)forPosition:(CGPoint)position withAbsolutePosition:(CGPoint)absolutePosition withNumberOfTouches:(NSUInteger)numberOfTouches; ++ (RNGestureHandlerEventExtraData *)forPosition:(CGPoint)position + withAbsolutePosition:(CGPoint)absolutePosition + withNumberOfTouches:(NSUInteger)numberOfTouches + withDuration:(NSUInteger)duration; + (RNGestureHandlerEventExtraData *)forPan:(CGPoint)position withAbsolutePosition:(CGPoint)absolutePosition withTranslation:(CGPoint)translation diff --git a/ios/RNGestureHandlerEvents.m b/ios/RNGestureHandlerEvents.m index 2065f0e66..dd8b707f4 100644 --- a/ios/RNGestureHandlerEvents.m +++ b/ios/RNGestureHandlerEvents.m @@ -25,6 +25,22 @@ + (RNGestureHandlerEventExtraData *)forPosition:(CGPoint)position @"numberOfPointers": @(numberOfTouches)}]; } ++ (RNGestureHandlerEventExtraData *)forPosition:(CGPoint)position + withAbsolutePosition:(CGPoint)absolutePosition + withNumberOfTouches:(NSUInteger)numberOfTouches + withDuration:(NSUInteger)duration +{ + return [[RNGestureHandlerEventExtraData alloc] + initWithData:@{ + @"x": @(position.x), + @"y": @(position.y), + @"absoluteX": @(absolutePosition.x), + @"absoluteY": @(absolutePosition.y), + @"numberOfPointers": @(numberOfTouches), + @"duration":@(duration) + }]; +} + + (RNGestureHandlerEventExtraData *)forPan:(CGPoint)position withAbsolutePosition:(CGPoint)absolutePosition withTranslation:(CGPoint)translation diff --git a/src/handlers/gestureHandlers.ts b/src/handlers/gestureHandlers.ts index d2be2b4ec..93b6ebc4f 100644 --- a/src/handlers/gestureHandlers.ts +++ b/src/handlers/gestureHandlers.ts @@ -205,6 +205,7 @@ export type LongPressGestureHandlerEventPayload = { y: number; absoluteX: number; absoluteY: number; + duration: number; }; export interface LongPressGestureHandlerProps