Skip to content

Commit 90106dc

Browse files
julienR2rborn
authored andcommitted
add Android support for onPoiClick (react-native-maps#2050)
* add Android support for onPoiClick * add example of onPoiClick event handling * lint * typo * add support for GM on IOS * Update docs since onPoiClick is now available on Android and IOS.
1 parent ccefcf0 commit 90106dc

File tree

11 files changed

+159
-20
lines changed

11 files changed

+159
-20
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ To run examples:
264264

265265
```bash
266266
npm i
267-
npm start
267+
npm start
268268

269269
#Android
270270
npm run run:android
@@ -397,6 +397,12 @@ Enable lite mode on Android with `liteMode` prop. Ideal when having multiple map
397397

398398
![](http://i.giphy.com/qZ2lAf18s89na.gif)
399399

400+
### On Poi Click (Google Maps Only)
401+
402+
Poi are clickable, you can catch the event to get its information (usually to get the full detail from Google Place using the placeId).
403+
404+
![](https://media.giphy.com/media/3480VsCKnHr31uCLU3/giphy.gif)
405+
400406
### Animated Region
401407

402408
The MapView can accept an `AnimatedRegion` value as its `region` prop. This allows you to utilize the Animated API to control the map's center and zoom.

docs/mapview.md

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres
5151
| `onUserLocationChange` | `{ coordinate: LatLng }` | Callback that is called when the underlying map figures our users current location. Make sure **showsUserLocation** is set to *true* and that the provider is `"google"`.
5252
| `onPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user taps on the map.
5353
| `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
54+
| `onPoiClick` | `{ coordinate: LatLng, position: Point, placeId: string, name: string }` | Callback that is called when user click on a POI.
5455
| `onLongPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user makes a "long press" somewhere on the map.
5556
| `onMarkerPress` | | Callback that is called when a marker on the map is tapped by the user.
5657
| `onMarkerSelect` | | Callback that is called when a marker on the map becomes selected. This will be called when the callout for that marker is about to be shown. **Note**: iOS only.

example/App.js

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import MapKml from './examples/MapKml';
4040
import BugMarkerWontUpdate from './examples/BugMarkerWontUpdate';
4141
import ImageOverlayWithAssets from './examples/ImageOverlayWithAssets';
4242
import ImageOverlayWithURL from './examples/ImageOverlayWithURL';
43+
import OnPoiClick from './examples/OnPoiClick';
4344

4445
const IOS = Platform.OS === 'ios';
4546
const ANDROID = Platform.OS === 'android';
@@ -158,6 +159,7 @@ class App extends React.Component {
158159
[BugMarkerWontUpdate, 'BUG: Marker Won\'t Update (Android)', true],
159160
[ImageOverlayWithAssets, 'Image Overlay Component with Assets', true],
160161
[ImageOverlayWithURL, 'Image Overlay Component with URL', true],
162+
[OnPoiClick, 'On Poi Click', true],
161163
]
162164
// Filter out examples that are not yet supported for Google Maps on iOS.
163165
.filter(example => ANDROID || (IOS && (example[2] || !this.state.useGoogleMaps)))

example/examples/OnPoiClick.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import React from 'react';
2+
import {
3+
StyleSheet,
4+
View,
5+
Text,
6+
Dimensions,
7+
} from 'react-native';
8+
9+
import MapView, { Callout, Marker, ProviderPropType } from 'react-native-maps';
10+
11+
const { width, height } = Dimensions.get('window');
12+
13+
const ASPECT_RATIO = width / height;
14+
const LATITUDE = 37.78825;
15+
const LONGITUDE = -122.4324;
16+
const LATITUDE_DELTA = 0.0922;
17+
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
18+
19+
class OnPoiClick extends React.Component {
20+
constructor(props) {
21+
super(props);
22+
23+
this.state = {
24+
region: {
25+
latitude: LATITUDE,
26+
longitude: LONGITUDE,
27+
latitudeDelta: LATITUDE_DELTA,
28+
longitudeDelta: LONGITUDE_DELTA,
29+
},
30+
poi: null,
31+
};
32+
33+
this.onPoiClick = this.onPoiClick.bind(this);
34+
}
35+
36+
onPoiClick(e) {
37+
const poi = e.nativeEvent;
38+
39+
this.setState({
40+
poi,
41+
});
42+
}
43+
44+
render() {
45+
return (
46+
<View style={styles.container}>
47+
<MapView
48+
provider={this.props.provider}
49+
style={styles.map}
50+
initialRegion={this.state.region}
51+
onPoiClick={this.onPoiClick}
52+
>
53+
{this.state.poi && (
54+
<Marker
55+
coordinate={this.state.poi.coordinate}
56+
>
57+
<Callout>
58+
<View>
59+
<Text>Place Id: { this.state.poi.placeId }</Text>
60+
<Text>Name: { this.state.poi.name }</Text>
61+
</View>
62+
</Callout>
63+
</Marker>
64+
)}
65+
</MapView>
66+
</View>
67+
);
68+
}
69+
}
70+
71+
OnPoiClick.propTypes = {
72+
provider: ProviderPropType,
73+
};
74+
75+
const styles = StyleSheet.create({
76+
container: {
77+
...StyleSheet.absoluteFillObject,
78+
justifyContent: 'flex-end',
79+
alignItems: 'center',
80+
},
81+
map: {
82+
...StyleSheet.absoluteFillObject,
83+
},
84+
});
85+
86+
export default OnPoiClick;

index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ declare module "react-native-maps" {
8989
onMarkerDragStart?: (value: { coordinate: LatLng, position: Point }) => void;
9090
onMarkerDrag?: (value: { coordinate: LatLng, position: Point }) => void;
9191
onMarkerDragEnd?: (value: { coordinate: LatLng, position: Point }) => void;
92+
onPoiClick?: (value: {coordinate: LatLng, position: Point, placeId: string, name: string }) => void;
9293
minZoomLevel?: number;
9394
maxZoomLevel?: number;
9495
kmlSrc?: string;

lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,8 @@ public Map getExportedCustomDirectEventTypeConstants() {
322322
"onMarkerDrag", MapBuilder.of("registrationName", "onMarkerDrag"),
323323
"onMarkerDragEnd", MapBuilder.of("registrationName", "onMarkerDragEnd"),
324324
"onPanDrag", MapBuilder.of("registrationName", "onPanDrag"),
325-
"onKmlReady", MapBuilder.of("registrationName", "onKmlReady")
325+
"onKmlReady", MapBuilder.of("registrationName", "onKmlReady"),
326+
"onPoiClick", MapBuilder.of("registrationName", "onPoiClick")
326327
));
327328

328329
return map;

lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.google.android.gms.maps.model.LatLngBounds;
4444
import com.google.android.gms.maps.model.Marker;
4545
import com.google.android.gms.maps.model.MarkerOptions;
46+
import com.google.android.gms.maps.model.PointOfInterest;
4647
import com.google.android.gms.maps.model.Polygon;
4748
import com.google.android.gms.maps.model.Polyline;
4849
import com.google.maps.android.data.kml.KmlContainer;
@@ -64,7 +65,7 @@
6465
import static android.support.v4.content.PermissionChecker.checkSelfPermission;
6566

6667
public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter,
67-
GoogleMap.OnMarkerDragListener, OnMapReadyCallback {
68+
GoogleMap.OnMarkerDragListener, OnMapReadyCallback, GoogleMap.OnPoiClickListener {
6869
public GoogleMap map;
6970
private KmlLayer kmlLayer;
7071
private ProgressBar mapLoadingProgressBar;
@@ -178,6 +179,7 @@ public void onMapReady(final GoogleMap map) {
178179
this.map = map;
179180
this.map.setInfoWindowAdapter(this);
180181
this.map.setOnMarkerDragListener(this);
182+
this.map.setOnPoiClickListener(this);
181183

182184
manager.pushEvent(context, this, "onMapReady", new WritableNativeMap());
183185

@@ -806,6 +808,16 @@ public void onMarkerDragEnd(Marker marker) {
806808
manager.pushEvent(context, markerView, "onDragEnd", event);
807809
}
808810

811+
@Override
812+
public void onPoiClick(PointOfInterest poi) {
813+
WritableMap event = makeClickEventData(poi.latLng);
814+
815+
event.putString("placeId", poi.placeId);
816+
event.putString("name", poi.name);
817+
818+
manager.pushEvent(context, this, "onPoiClick", event);
819+
}
820+
809821
private ProgressBar getMapLoadingProgressBar() {
810822
if (this.mapLoadingProgressBar == null) {
811823
this.mapLoadingProgressBar = new ProgressBar(getContext());

lib/components/MapView.js

+5
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,11 @@ const propTypes = {
382382
*/
383383
onPanDrag: PropTypes.func,
384384

385+
/**
386+
* Callback that is called when user click on a POI
387+
*/
388+
onPoiClick: PropTypes.func,
389+
385390
/**
386391
* Callback that is called when a marker on the map is tapped by the user.
387392
*/

lib/ios/AirGoogleMaps/AIRGoogleMap.h

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
@property (nonatomic, copy) RCTBubblingEventBlock onUserLocationChange;
2929
@property (nonatomic, copy) RCTBubblingEventBlock onMarkerPress;
3030
@property (nonatomic, copy) RCTBubblingEventBlock onChange;
31+
@property (nonatomic, copy) RCTBubblingEventBlock onPoiClick;
3132
@property (nonatomic, copy) RCTDirectEventBlock onRegionChange;
3233
@property (nonatomic, copy) RCTDirectEventBlock onRegionChangeComplete;
3334
@property (nonatomic, strong) NSMutableArray *markers;
@@ -57,6 +58,7 @@
5758
- (void)didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate;
5859
- (void)didChangeCameraPosition:(GMSCameraPosition *)position;
5960
- (void)idleAtCameraPosition:(GMSCameraPosition *)position;
61+
- (void)didTapPOIWithPlaceID:(NSString *)placeID name:(NSString *) name location:(CLLocationCoordinate2D) location;
6062

6163
+ (MKCoordinateRegion)makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position;
6264
+ (GMSCameraPosition*)makeGMSCameraPositionFromMap:(GMSMapView *)map andMKCoordinateRegion:(MKCoordinateRegion)region;

lib/ios/AirGoogleMaps/AIRGoogleMap.m

+25-11
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,20 @@ - (void)didChangeCameraPosition:(GMSCameraPosition *)position {
272272
if (self.onChange) self.onChange(event);
273273
}
274274

275+
- (void)didTapPOIWithPlaceID:(NSString *)placeID
276+
name:(NSString *)name
277+
location:(CLLocationCoordinate2D)location {
278+
id event = @{@"placeId": placeID,
279+
@"name": name,
280+
@"coordinate": @{
281+
@"latitude": @(location.latitude),
282+
@"longitude": @(location.longitude)
283+
}
284+
};
285+
286+
if (self.onPoiClick) self.onPoiClick(event);
287+
}
288+
275289
- (void)idleAtCameraPosition:(GMSCameraPosition *)position {
276290
id event = @{@"continuous": @NO,
277291
@"region": regionAsJSON([AIRGoogleMap makeGMSCameraPositionFromMap:self andGMSCameraPosition:position]),
@@ -456,7 +470,7 @@ + (NSString *)GetIconUrl:(GMUPlacemark *) marker parser:(GMUKMLParser *) parser
456470
}
457471
}
458472
}
459-
473+
460474
return marker.style.iconUrl;
461475
}
462476

@@ -465,28 +479,28 @@ - (NSString *)KmlSrc {
465479
}
466480

467481
- (void)setKmlSrc:(NSString *)kmlUrl {
468-
482+
469483
_kmlSrc = kmlUrl;
470-
484+
471485
NSURL *url = [NSURL URLWithString:kmlUrl];
472486
NSData *urlData = nil;
473-
487+
474488
if ([url isFileURL]) {
475489
urlData = [NSData dataWithContentsOfURL:url];
476490
} else {
477491
urlData = [[NSFileManager defaultManager] contentsAtPath:kmlUrl];
478492
}
479-
493+
480494
GMUKMLParser *parser = [[GMUKMLParser alloc] initWithData:urlData];
481495
[parser parse];
482-
496+
483497
NSUInteger index = 0;
484498
NSMutableArray *markers = [[NSMutableArray alloc]init];
485499

486500
for (GMUPlacemark *place in parser.placemarks) {
487-
501+
488502
CLLocationCoordinate2D location =((GMUPoint *) place.geometry).coordinate;
489-
503+
490504
AIRGoogleMapMarker *marker = (AIRGoogleMapMarker *)[[AIRGoogleMapMarkerManager alloc] view];
491505
if (!marker.bridge) {
492506
marker.bridge = _bridge;
@@ -499,9 +513,9 @@ - (void)setKmlSrc:(NSString *)kmlUrl {
499513
marker.imageSrc = [AIRGoogleMap GetIconUrl:place parser:parser];
500514
marker.layer.backgroundColor = [UIColor clearColor].CGColor;
501515
marker.layer.position = CGPointZero;
502-
516+
503517
[self insertReactSubview:(UIView *) marker atIndex:index];
504-
518+
505519
[markers addObject:@{@"id": marker.identifier,
506520
@"title": marker.title,
507521
@"description": marker.subtitle,
@@ -513,7 +527,7 @@ - (void)setKmlSrc:(NSString *)kmlUrl {
513527

514528
index++;
515529
}
516-
530+
517531
id event = @{@"markers": markers};
518532
if (self.onKmlReady) self.onKmlReady(event);
519533
}

lib/ios/AirGoogleMaps/AIRGoogleMapManager.m

+15-6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ - (UIView *)view
7171
RCT_EXPORT_VIEW_PROPERTY(onMarkerPress, RCTDirectEventBlock)
7272
RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTDirectEventBlock)
7373
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock)
74+
RCT_EXPORT_VIEW_PROPERTY(onPoiClick, RCTDirectEventBlock)
7475
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType)
7576
RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
7677
RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
@@ -304,16 +305,16 @@ - (UIView *)view
304305
[coordinate[@"latitude"] doubleValue],
305306
[coordinate[@"longitude"] doubleValue]
306307
);
307-
308+
308309
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
309310
id view = viewRegistry[reactTag];
310311
if (![view isKindOfClass:[AIRGoogleMap class]]) {
311312
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
312313
} else {
313314
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
314-
315+
315316
CGPoint touchPoint = [mapView.projection pointForCoordinate:coord];
316-
317+
317318
callback(@[[NSNull null], @{
318319
@"x": @(touchPoint.x),
319320
@"y": @(touchPoint.y),
@@ -330,16 +331,16 @@ - (UIView *)view
330331
[point[@"x"] doubleValue],
331332
[point[@"y"] doubleValue]
332333
);
333-
334+
334335
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
335336
id view = viewRegistry[reactTag];
336337
if (![view isKindOfClass:[AIRGoogleMap class]]) {
337338
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
338339
} else {
339340
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
340-
341+
341342
CLLocationCoordinate2D coordinate = [mapView.projection coordinateForPoint:pt];
342-
343+
343344
callback(@[[NSNull null], @{
344345
@"latitude": @(coordinate.latitude),
345346
@"longitude": @(coordinate.longitude),
@@ -437,4 +438,12 @@ - (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker {
437438
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
438439
[aMarker.fakeMarker didDragMarker:aMarker];
439440
}
441+
442+
- (void)mapView:(GMSMapView *)mapView
443+
didTapPOIWithPlaceID:(NSString *)placeID
444+
name:(NSString *)name
445+
location:(CLLocationCoordinate2D)location {
446+
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
447+
[googleMapView didTapPOIWithPlaceID:placeID name:name location:location];
448+
}
440449
@end

0 commit comments

Comments
 (0)