Skip to content
Merged
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,9 @@ the `<Marker />`'s `title` and `description` props.
Custom callout views can be the entire tooltip bubble, or just the content inside of the system
default bubble.

To handle press on specific subview of callout use `<CalloutSubview />` with `onPress`.
See `Callouts.js` example.

![](http://i.giphy.com/xT77XNePGnMIIDpbnq.gif) ![](http://i.giphy.com/xT77YdU0HXryvoRqaQ.gif)


Expand Down
26 changes: 25 additions & 1 deletion docs/callout.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,34 @@
| Prop | Type | Default | Note |
|---|---|---|---|
| `tooltip` | `Boolean` | `false` | If `false`, a default "tooltip" bubble window will be drawn around this callouts children. If `true`, the child views can fully customize their appearance, including any "bubble" like styles.

| `alphaHitTest` | `Boolean` | `false` | If `true`, clicks on transparent areas in callout will be passed to map. **Note**: iOS only.

## Events

| Event Name | Returns | Notes
|---|---|---|
| `onPress` | | Callback that is called when the user presses on the callout



---



# `<CalloutSubview />` Component API

**Note**: Supported on iOS only.
Use to handle press on specific subview of callout.
Put this component inside `<Callout />`.

## Events

| Event Name | Returns | Notes
|---|---|---|
| `onPress` | | Callback that is called when the user presses on this subview inside callout

## Notes
Native press event has property `action`, which is:
- `callout-press` (or `marker-overlay-press` for GoogleMaps on iOS) for press on `<Callout />`
- `callout-inside-press` (or `marker-inside-overlay-press` for GoogleMaps on iOS) for press on `<CalloutSubview />`

11 changes: 11 additions & 0 deletions docs/mapview.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
| `showsIndoors` | `Boolean` | `true` | A Boolean indicating whether indoor maps should be enabled.
| `showsIndoorLevelPicker` | `Boolean` | `false` | A Boolean indicating whether indoor level picker should be enabled. **Note:** Google Maps only (either Android or iOS with `PROVIDER_GOOGLE`).
| `zoomEnabled` | `Boolean` | `true` | If `false` the user won't be able to pinch/zoom the map.
| `zoomTapEnabled` | `Boolean` | `true` | If `false` the user won't be able to double tap to zoom the map. **Note:** But it will greatly decrease delay of tap gesture recognition. **Note:** Google Maps on iOS only
| `zoomControlEnabled` | `Boolean` | `true` | If `false` the zoom control at the bottom right of the map won't be visible **Note:** Android only.
| `minZoomLevel` | `Number` | `0` | Minimum zoom value for the map, must be between 0 and 20
| `maxZoomLevel` | `Number` | `20` | Maximum zoom value for the map, must be between 0 and 20
Expand Down Expand Up @@ -89,6 +90,7 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres
| `fitToCoordinates` | `coordinates: Array<LatLng>, options: { edgePadding: EdgePadding, animated: Boolean }` | If called in `ComponentDidMount` in android, it will cause an exception. It is recommended to call it from the MapView `onLayout` event.
| `pointForCoordinate` | `coordinate: LatLng` | Converts a map coordinate to a view coordinate (`Point`). Returns a `Promise<Point>`.
| `coordinateForPoint` | `point: Point` | Converts a view coordinate (`Point`) to a map coordinate. Returns a `Promise<Coordinate>`.
| `getMarkersFrames` | `onlyVisible: Boolean` | Get markers' centers and frames in view coordinates. Returns a `Promise<{ "markerID" : { point: Point, frame: Frame } }>`. **Note**: iOS only.



Expand Down Expand Up @@ -156,6 +158,15 @@ type Point {
}
```

```
type Frame {
x: Number,
y: Number,
width: Number,
height: Number,
}
```

```
enum MapType : String {
"standard",
Expand Down
1 change: 1 addition & 0 deletions docs/marker.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ To access event data, you will need to use `e.nativeEvent`. For example, `onPres
|---|---|---|
| `showCallout` | | Shows the callout for this marker
| `hideCallout` | | Hides the callout for this marker
| `redrawCallout` | | Causes a redraw of the marker's callout. Useful for Google Maps on iOS. **Note**: iOS only.
| `animateMarkerToCoordinate` | `coordinate: LatLng, duration: number` | Animates marker movement. **Note**: Android only
| `redraw` | | Causes a redraw of the marker. Useful when there are updates to the marker and `tracksViewChanges` comes with a cost that is too high.

Expand Down
59 changes: 51 additions & 8 deletions example/examples/Callouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
Text,
Dimensions,
TouchableOpacity,
Alert,
} from 'react-native';
import MapView, { Marker, Callout, ProviderPropType } from 'react-native-maps';
import MapView, { Marker, Callout, CalloutSubview, ProviderPropType } from 'react-native-maps';
import CustomCallout from './CustomCallout';

const { width, height } = Dimensions.get('window');

const ASPECT_RATIO = width / height;
const LATITUDE = 37.78825;
const LONGITUDE = -122.4324;
Expand All @@ -23,6 +23,7 @@ class Callouts extends React.Component {
super(props);

this.state = {
cnt: 0,
region: {
latitude: LATITUDE,
longitude: LONGITUDE,
Expand All @@ -36,6 +37,12 @@ class Callouts extends React.Component {
longitude: LONGITUDE + SPACE,
},
},
{
coordinate: {
latitude: LATITUDE + SPACE,
longitude: LONGITUDE - SPACE,
},
},
{
coordinate: {
latitude: LATITUDE,
Expand All @@ -44,8 +51,8 @@ class Callouts extends React.Component {
},
{
coordinate: {
latitude: LATITUDE + SPACE,
longitude: LONGITUDE - SPACE,
latitude: LATITUDE,
longitude: LONGITUDE - (SPACE / 2),
},
},
],
Expand All @@ -68,6 +75,7 @@ class Callouts extends React.Component {
provider={this.props.provider}
style={styles.map}
initialRegion={region}
zoomTapEnabled={false}
>
<Marker
ref={ref => { this.marker1 = ref; }}
Expand All @@ -79,7 +87,6 @@ class Callouts extends React.Component {
coordinate={markers[1].coordinate}
>
<Callout style={styles.plainView}>

<View>
<Text>This is a plain view</Text>
</View>
Expand All @@ -89,13 +96,39 @@ class Callouts extends React.Component {
coordinate={markers[2].coordinate}
calloutOffset={{ x: -8, y: 28 }}
calloutAnchor={{ x: 0.5, y: 0.4 }}
ref={ref => { this.marker2 = ref; }}
>
<Callout tooltip style={styles.customView}>
<Callout
alphaHitTest
tooltip onPress={(e) => {
if (e.nativeEvent.action === 'marker-inside-overlay-press' ||
e.nativeEvent.action === 'callout-inside-press') {
return;
}

Alert.alert('callout pressed');
}} style={styles.customView}
>
<CustomCallout>
<Text>This is a custom callout bubble view</Text>
<Text>{`This is a custom callout bubble view ${this.state.cnt}`}</Text>
<CalloutSubview
onPress={() => {
this.setState({ cnt: this.state.cnt + 1 }, () => {
this.marker2.redrawCallout();
});
}} style={[styles.calloutButton]}
>
<Text>Click me</Text>
</CalloutSubview>
</CustomCallout>
</Callout>
</Marker>
<Marker
ref={ref => { this.marker4 = ref; }}
coordinate={markers[3].coordinate}
title="You can also open this callout"
description="by pressing on transparent area of custom callout" // eslint-disable-line max-len
/>
</MapView>
<View style={styles.buttonContainer}>
<View style={styles.bubble}>
Expand All @@ -122,7 +155,7 @@ Callouts.propTypes = {
const styles = StyleSheet.create({
customView: {
width: 140,
height: 100,
height: 140,
},
plainView: {
width: 60,
Expand Down Expand Up @@ -157,6 +190,16 @@ const styles = StyleSheet.create({
marginVertical: 20,
backgroundColor: 'transparent',
},
calloutButton: {
width: 'auto',
backgroundColor: 'rgba(255,255,255,0.7)',
paddingHorizontal: 6,
paddingVertical: 6,
borderRadius: 12,
alignItems: 'center',
marginHorizontal: 10,
marginVertical: 10,
},
});

export default Callouts;
14 changes: 14 additions & 0 deletions example/examples/FitToCoordinates.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ const MARKERS = [
const DEFAULT_PADDING = { top: 40, right: 40, bottom: 40, left: 40 };

class FitToCoordinates extends React.Component {
async logFrames() {
const visMarkersFrames = await this.map.getMarkersFrames(true);
console.log('Visible markers frames:', visMarkersFrames);
const allMarkersFrames = await this.map.getMarkersFrames();
console.log('All markers frames:', allMarkersFrames);
}

fitPadding() {
this.map.fitToCoordinates([MARKERS[2], MARKERS[3]], {
edgePadding: { top: 100, right: 100, bottom: 100, left: 100 },
Expand Down Expand Up @@ -72,6 +79,7 @@ class FitToCoordinates extends React.Component {
{MARKERS.map((marker, i) => (
<Marker
key={i}
identifier={`id${i}`}
coordinate={marker}
/>
))}
Expand All @@ -95,6 +103,12 @@ class FitToCoordinates extends React.Component {
>
<Text>Fit All Markers</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.logFrames()}
style={[styles.bubble, styles.button]}
>
<Text>Log markers frames</Text>
</TouchableOpacity>
</View>
</View>
);
Expand Down
17 changes: 17 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ declare module "react-native-maps" {
showsPointsOfInterest?: boolean;
showsCompass?: boolean;
zoomEnabled?: boolean;
zoomTapEnabled?: boolean;
zoomControlEnabled?: boolean;
rotateEnabled?: boolean;
cacheEnabled?: boolean;
Expand Down Expand Up @@ -290,6 +291,11 @@ declare module "react-native-maps" {
* Hides the callout for this marker
*/
hideCallout(): void;
/**
* Redraws the callout for this marker
* __iOS only__
*/
redrawCallout(): void;
/**
* Animates marker movement.
* __Android only__
Expand All @@ -312,6 +318,17 @@ declare module "react-native-maps" {
export class Callout extends React.Component<MapCalloutProps, any> {
}

// =======================================================================
// CalloutSubview
// =======================================================================

export interface MapCalloutSubviewProps extends ViewProperties {
onPress?: (event: MapEvent<{ action: 'callout-inside-press' }>) => void;
}

export class CalloutSubview extends React.Component<MapCalloutSubviewProps, any> {
}

// =======================================================================
// Polyline
// =======================================================================
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as Circle } from './lib/components/MapCircle.js';
export { default as UrlTile } from './lib/components/MapUrlTile.js';
export { default as LocalTile } from './lib/components/MapLocalTile.js';
export { default as Callout } from './lib/components/MapCallout.js';
export { default as CalloutSubview } from './lib/components/MapCalloutSubview.js';
export { default as AnimatedRegion } from './lib/components/AnimatedRegion.js';

export { Marker, Overlay };
Expand Down
2 changes: 2 additions & 0 deletions lib/components/MapCallout.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ const propTypes = {
...viewPropTypes,
tooltip: PropTypes.bool,
onPress: PropTypes.func,
alphaHitTest: PropTypes.bool,
};

const defaultProps = {
tooltip: false,
alphaHitTest: false,
};

class MapCallout extends React.Component {
Expand Down
50 changes: 50 additions & 0 deletions lib/components/MapCalloutSubview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import PropTypes from 'prop-types';
import React from 'react';
import {
StyleSheet,
ViewPropTypes,
View,
} from 'react-native';
import decorateMapComponent, {
SUPPORTED,
NOT_SUPPORTED,
} from './decorateMapComponent';

// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
const viewPropTypes = ViewPropTypes || View.propTypes;

const propTypes = {
...viewPropTypes,
onPress: PropTypes.func,
};

const defaultProps = {
};

class MapCalloutSubview extends React.Component {
render() {
const AIRMapCalloutSubview = this.getAirComponent();
return (<AIRMapCalloutSubview
{...this.props}
style={[styles.calloutSubview, this.props.style]}
/>);
}
}

MapCalloutSubview.propTypes = propTypes;
MapCalloutSubview.defaultProps = defaultProps;

const styles = StyleSheet.create({
calloutSubview: {
},
});

export default decorateMapComponent(MapCalloutSubview, {
componentType: 'CalloutSubview',
providers: {
google: {
ios: SUPPORTED,
android: NOT_SUPPORTED,
},
},
});
5 changes: 5 additions & 0 deletions lib/components/MapMarker.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ class MapMarker extends React.Component {

this.showCallout = this.showCallout.bind(this);
this.hideCallout = this.hideCallout.bind(this);
this.redrawCallout = this.redrawCallout.bind(this);
this.animateMarkerToCoordinate = this.animateMarkerToCoordinate.bind(this);
}

Expand All @@ -266,6 +267,10 @@ class MapMarker extends React.Component {
this._runCommand('hideCallout', []);
}

redrawCallout() {
this._runCommand('redrawCallout', []);
}

animateMarkerToCoordinate(coordinate, duration) {
this._runCommand('animateMarkerToCoordinate', [coordinate, duration || 500]);
}
Expand Down
Loading