[MapView] Support for annotation callouts, annotation press, callout presses and pin animation

Summary:
Started from here - https://github.com/facebook/react-native/issues/1120. Most functionality for annotations were missing so I started implementing and somehow got caught up until the entire thing was done.

![screen shot 2015-05-12 at 10 07 43 pm](https://cloud.githubusercontent.com/assets/688326/7588677/8479a7a4-f8f9-11e4-99a4-1dc3c7691810.png)

2 new events:
- callout presses (left / right)
- annotation presses

6 new properties for annotations:
- hasLeftCallout
- hasRightCallout
- onLeftCalloutPress
- onRightCalloutPress
- animateDrop
- id

1 new property for MapView
- onAnnotationPress

---
Now the important thing is, that I implemented all of this the way "I would do it". I am not sure this is the 'reacty' way so please let me know my mistakes 😄

The problem is that there is no real way to identify annotations which makes it difficult to distinguish which one got clicked. The idea is to pass a `id` and whether it has callouts the entire way with the annotation. I had to
Closes https://github.com/facebook/react-native/pull/1247
Github Author: David Mohl <me@dave.cx>

Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
David Mohl
2015-06-25 09:07:19 -07:00
parent 3c5b4b0a9f
commit 99bc08cf61
13 changed files with 313 additions and 54 deletions

View File

@@ -35,6 +35,34 @@ type MapRegion = {
var MapView = React.createClass({
mixins: [NativeMethodsMixin],
checkAnnotationIds: function (annotations: Array<Object>) {
var newAnnotations = annotations.map(function (annotation) {
if (!annotation.id) {
// TODO: add a base64 (or similar) encoder here
annotation.id = encodeURIComponent(JSON.stringify(annotation));
}
return annotation;
});
this.setState({
annotations: newAnnotations
});
},
componentWillMount: function() {
if (this.props.annotations) {
this.checkAnnotationIds(this.props.annotations);
}
},
componentWillReceiveProps: function(nextProps: Object) {
if (nextProps.annotations) {
this.checkAnnotationIds(nextProps.annotations);
}
},
propTypes: {
/**
* Used to style and layout the `MapView`. See `StyleSheet.js` and
@@ -84,14 +112,14 @@ var MapView = React.createClass({
/**
* The map type to be displayed.
*
*
* - standard: standard road map (default)
* - satellite: satellite view
* - hybrid: satellite view with roads and points of interest overlayed
*/
mapType: React.PropTypes.oneOf([
'standard',
'satellite',
'standard',
'satellite',
'hybrid',
]),
@@ -126,11 +154,34 @@ var MapView = React.createClass({
latitude: React.PropTypes.number.isRequired,
longitude: React.PropTypes.number.isRequired,
/**
* Whether the pin drop should be animated or not
*/
animateDrop: React.PropTypes.bool,
/**
* Annotation title/subtile.
*/
title: React.PropTypes.string,
subtitle: React.PropTypes.string,
/**
* Whether the Annotation has callout buttons.
*/
hasLeftCallout: React.PropTypes.bool,
hasRightCallout: React.PropTypes.bool,
/**
* Event handlers for callout buttons.
*/
onLeftCalloutPress: React.PropTypes.func,
onRightCalloutPress: React.PropTypes.func,
/**
* annotation id
*/
id: React.PropTypes.string
})),
/**
@@ -158,6 +209,11 @@ var MapView = React.createClass({
* Callback that is called once, when the user is done moving the map.
*/
onRegionChangeComplete: React.PropTypes.func,
/**
* Callback that is called once, when the user is clicked on a annotation.
*/
onAnnotationPress: React.PropTypes.func,
},
_onChange: function(event: Event) {
@@ -170,8 +226,34 @@ var MapView = React.createClass({
}
},
_onPress: function(event: Event) {
if (event.nativeEvent.action === 'annotation-click') {
this.props.onAnnotationPress && this.props.onAnnotationPress(event.nativeEvent.annotation);
}
if (event.nativeEvent.action === 'callout-click') {
if (!this.props.annotations) {
return;
}
// Find the annotation with the id of what has been pressed
for (var i = 0; i < this.props.annotations.length; i++) {
var annotation = this.props.annotations[i];
if (annotation.id === event.nativeEvent.annotationId) {
// Pass the right function
if (event.nativeEvent.side === 'left') {
annotation.onLeftCalloutPress && annotation.onLeftCalloutPress(event.nativeEvent);
} else if (event.nativeEvent.side === 'right') {
annotation.onRightCalloutPress && annotation.onRightCalloutPress(event.nativeEvent);
}
}
}
}
},
render: function() {
return <RCTMap {...this.props} onChange={this._onChange} />;
return <RCTMap {...this.props} onPress={this._onPress} onChange={this._onChange} />;
},
});