From 12c6e36e16f9e28e4ac3eec7d8f6740f1da12342 Mon Sep 17 00:00:00 2001 From: Poyan Nabati Date: Wed, 3 Jul 2019 13:00:57 +0300 Subject: [PATCH] Add onDoublePress callback Add to Google Maps on Android and Apple Maps on iOS --- docs/mapview.md | 1 + index.d.ts | 1 + .../android/react/maps/AirMapManager.java | 3 +- .../airbnb/android/react/maps/AirMapView.java | 13 ++++++ lib/components/MapView.js | 5 +++ lib/ios/AirMaps/AIRMap.h | 1 + lib/ios/AirMaps/AIRMapManager.m | 40 +++++++++++++++++-- 7 files changed, 60 insertions(+), 4 deletions(-) diff --git a/docs/mapview.md b/docs/mapview.md index 00d11c259..e465d09cf 100644 --- a/docs/mapview.md +++ b/docs/mapview.md @@ -56,6 +56,7 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres | `onRegionChangeComplete` | `Region` | Callback that is called once when the region changes, such as when the user is done moving the map. | `onUserLocationChange` | `{ coordinate: Location }` | Callback that is called when the underlying map figures our users current location (coordinate also includes isFromMockProvider value for Android API 18 and above). Make sure **showsUserLocation** is set to *true* and that the provider is `"google"`. | `onPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user taps on the map. +| `onDoublePress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user double taps on the map. | `onPanDrag` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user presses and drags the map. **NOTE**: for iOS `scrollEnabled` should be set to false to trigger the event | `onPoiClick` | `{ coordinate: LatLng, position: Point, placeId: string, name: string }` | Callback that is called when user click on a POI. | `onLongPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user makes a "long press" somewhere on the map. diff --git a/index.d.ts b/index.d.ts index 7446fba44..5fc317098 100644 --- a/index.d.ts +++ b/index.d.ts @@ -221,6 +221,7 @@ declare module "react-native-maps" { onRegionChange?: (region: Region) => void; onRegionChangeComplete?: (region: Region) => void; onPress?: (event: MapEvent) => void; + onDoublePress?: (event: MapEvent) => void; onLongPress?: (event: MapEvent) => void; onUserLocationChange?: (event: EventUserLocation) => void; onPanDrag?: (event: MapEvent) => void; diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java index 2be486af7..680a8f203 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java @@ -377,7 +377,8 @@ public Map getExportedCustomDirectEventTypeConstants() { map.putAll(MapBuilder.of( "onIndoorLevelActivated", MapBuilder.of("registrationName", "onIndoorLevelActivated"), - "onIndoorBuildingFocused", MapBuilder.of("registrationName", "onIndoorBuildingFocused") + "onIndoorBuildingFocused", MapBuilder.of("registrationName", "onIndoorBuildingFocused"), + "onDoublePress", MapBuilder.of("registrationName", "onDoublePress") )); return map; diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java index 397d4a6f4..161a8703c 100644 --- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java +++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java @@ -167,6 +167,12 @@ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, } return false; } + + @Override + public boolean onDoubleTap(MotionEvent ev) { + onDoublePress(ev); + return false; + } }); this.addOnLayoutChangeListener(new OnLayoutChangeListener() { @@ -1057,6 +1063,13 @@ public void onPanDrag(MotionEvent ev) { manager.pushEvent(context, this, "onPanDrag", event); } + public void onDoublePress(MotionEvent ev) { + Point point = new Point((int) ev.getX(), (int) ev.getY()); + LatLng coords = this.map.getProjection().fromScreenLocation(point); + WritableMap event = makeClickEventData(coords); + manager.pushEvent(context, this, "onDoublePress", event); + } + public void setKmlSrc(String kmlSrc) { try { InputStream kmlStream = new FileUtil(context).execute(kmlSrc).get(); diff --git a/lib/components/MapView.js b/lib/components/MapView.js index 390fa253c..ff2c98566 100644 --- a/lib/components/MapView.js +++ b/lib/components/MapView.js @@ -420,6 +420,11 @@ const propTypes = { */ onPress: PropTypes.func, + /** + * Callback that is called when user double taps on the map. + */ + onDoublePress: PropTypes.func, + /** * Callback that is called when user makes a "long press" somewhere on the map. */ diff --git a/lib/ios/AirMaps/AIRMap.h b/lib/ios/AirMaps/AIRMap.h index e70d8f14c..751bef9bd 100644 --- a/lib/ios/AirMaps/AIRMap.h +++ b/lib/ios/AirMaps/AIRMap.h @@ -56,6 +56,7 @@ extern const NSInteger AIRMapMaxZoomLevel; @property (nonatomic, copy) RCTBubblingEventBlock onChange; @property (nonatomic, copy) RCTBubblingEventBlock onPress; @property (nonatomic, copy) RCTBubblingEventBlock onPanDrag; +@property (nonatomic, copy) RCTBubblingEventBlock onDoublePress; @property (nonatomic, copy) RCTBubblingEventBlock onLongPress; @property (nonatomic, copy) RCTDirectEventBlock onMarkerPress; @property (nonatomic, copy) RCTDirectEventBlock onMarkerSelect; diff --git a/lib/ios/AirMaps/AIRMapManager.m b/lib/ios/AirMaps/AIRMapManager.m index 63c93b577..be320319c 100644 --- a/lib/ios/AirMaps/AIRMapManager.m +++ b/lib/ios/AirMaps/AIRMapManager.m @@ -35,7 +35,9 @@ static NSString *const RCTMapViewKey = @"MapView"; -@interface AIRMapManager() +@interface AIRMapManager() + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer; @end @@ -55,18 +57,26 @@ - (UIView *)view // MKMapView doesn't report tap events, so we attach gesture recognizers to it UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapTap:)]; + UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDoubleTap:)]; + [doubleTap setNumberOfTapsRequired:2]; + [tap requireGestureRecognizerToFail:doubleTap]; + UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapLongPress:)]; UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)]; [drag setMinimumNumberOfTouches:1]; [drag setMaximumNumberOfTouches:1]; // setting this to NO allows the parent MapView to continue receiving marker selection events tap.cancelsTouchesInView = NO; + doubleTap.cancelsTouchesInView = NO; longPress.cancelsTouchesInView = NO; - + + doubleTap.delegate = self; + // disable drag by default drag.enabled = NO; - + [map addGestureRecognizer:tap]; + [map addGestureRecognizer:doubleTap]; [map addGestureRecognizer:longPress]; [map addGestureRecognizer:drag]; @@ -102,6 +112,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(onPanDrag, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onLongPress, RCTBubblingEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onDoublePress, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMarkerPress, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMarkerSelect, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMarkerDeselect, RCTDirectEventBlock) @@ -752,6 +763,25 @@ - (void)handleMapDrag:(UIPanGestureRecognizer*)recognizer { } +- (void)handleMapDoubleTap:(UIPanGestureRecognizer*)recognizer { + AIRMap *map = (AIRMap *)recognizer.view; + if (!map.onDoublePress) return; + + CGPoint touchPoint = [recognizer locationInView:map]; + CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map]; + map.onDoublePress(@{ + @"coordinate": @{ + @"latitude": @(coord.latitude), + @"longitude": @(coord.longitude), + }, + @"position": @{ + @"x": @(touchPoint.x), + @"y": @(touchPoint.y), + }, + }); + +} + - (void)handleMapLongPress:(UITapGestureRecognizer *)recognizer { @@ -1249,4 +1279,8 @@ - (double) zoomLevel:(AIRMap *)mapView { return zoomLevel; } +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + return YES; +} + @end