userLocationButton padding - move button only - react-native

Using react-native-maps, in my mapView, I have enabled my userLocationButton. You can see this rendered in the bottom right hand corner by default. I would like to be able to position this button specifically without it having an impact on the entire mapView.
I have tried mapPadding which you can see in my example but that seems to move the entire view which you can see by watching the 'google' text in the bottom left by default.
How can I position the userLocation button individually? Also, if I wanted to change the look of the button, how could I render a custom button? Worst case scenario I can just make my own.
I have the code below as well as a snack example here. Please run on IOS.
Thank you for any insight at all!
export default class Map extends React.Component {
render() {
return (
<View style={{...StyleSheet.absoluteFillObject}}>
<MapView
mapPadding={{bottom: 100}}
style={styles.map}
provider={PROVIDER_GOOGLE}
showsUserLocation={true}
showsMyLocationButton={true}>
</MapView>
</View>
);
}
}
const styles = ScaledSheet.create({
map: {
...StyleSheet.absoluteFillObject
},

I have searched before and I couldn't find the answer.
So I custom a button. I create a TouchableOpacity in an absolute view.
<TouchableOpacity
style={styles.circleView}
onPress={() => {
setFollowUser(true);
}}>
<Image
source={Target}
style={{
height: 20,
width: 20,
}}
tintColor={MediumBlue}
/>
</TouchableOpacity>
and in <MapView> I use
onUserLocationChange={userLocation => {
followUser === true &&
mapRef.current.animateToRegion(
{
latitude: userLocation.nativeEvent.coordinate.latitude,
longitude: userLocation.nativeEvent.coordinate.longitude,
latitudeDelta: initLatDelta,
longitudeDelta: initLongDelta,
},
1000,
);
}}
It works for me on Android.
If you dont want to follow user's location everytime, you can call it only once or use react-native-geolocation-service

Related

react-native-maps callout content not updated on change

I am trying to update the content of a <Callout> tag on a google maps view using the react-native-maps npm package. I would like to dynamically load extra content after a map marker is pressed. I have simplified my code to the example below:-
I have already tried using the tracksInfoWindowChanges attribute on the marker, and the showCallout() method to attempt to manually trigger a re-render. I am using android so the iOS only options such as redrawCallout() method are not available.
const MyMap = (props) => {
const [marker, setMarker] = useState({});
return (
<MapView
showsUserLocation
zoomControlEnabled={true}
zoomEnabled={true}
region={{
latitude: 0,
longitude: 0,
latitudeDelta: 0.03,
longitudeDelta: 0.03,
}}>
<Marker
coordinate={{latitude: 0, longitude: 0}}
onPress={(e) => {
setMarker({ title: 'Test'});
}}>
<View>
<Icon name='key' size={40} color='#384963'</Icon>
</View>
<Callout>
<Text>{marker.title}</Text>
</Callout>
</Marker>
</MapView>
);
}
Is it possible to trigger a re-render of the content after the Callout has been rendered once? From debugging I can see that the component renders after I update my marker state, however the content is not visible until I manually close the Callout and re-opened it.
I am having the exact same problem. The suggestion for android, as per this issue, is to use showCallout(). Below is my work-around for this issue using showCallout():
const MyMap = (props) => {
const [marker, setMarker] = useState({});
let markerRef = useRef(null);
useEffect(() => {
if (markerRef.current) {
markerRef.current.showCallout();
}
})
return (
<MapView
showsUserLocation
zoomControlEnabled={true}
zoomEnabled={true}
region={{
latitude: 0,
longitude: 0,
latitudeDelta: 0.03,
longitudeDelta: 0.03,
}}>
<Marker
ref={markerRef}
coordinate={{latitude: 0, longitude: 0}}
onPress={(e) => {
setMarker({title: `Test ${Math.floor(Math.random() * 10)}`});
}}>
<View>
<Icon name='key' size={40} color='#384963' />
</View>
<Callout>
<Text>{marker.title}</Text>
</Callout>
</Marker>
</MapView>
);
}
Briefly, I added a markerRef and call markerRef.current.showCallout() in useEffect(). What this achieves, if I am not mistaken, is that each time MyMap gets re-rendered, the callout will be forced to show again. I also changed the onPress such that the effect of callout re-rendering is more apparent.
Note 1: Each time the marker is pressed, the callout shall have its text updated.
Note 2: If you have multiple markers and callouts, and you want to update only the callout that is currently in view, you will have to add another check in useEffect(). Something like: if (markerRef.current && selectedMarker === 'markerID') to make sure that only the desired callout is re-rendered continuously.

react-native-maps inside Tab not working

I'm having trouble displaying my <MapView /> inside a Tab. I'm using react-native-scrollable-tab-view
The <MapView /> won't display in the map even after using : ...StyleSheet.absoluteFillObject. I can display the map only if I put a fix height. For example: height: 500.
Here is what my sample tab screen looks like.
styles = StyleSheet.create({
tabContent: {
flex: 1,
},
map: {
...StyleSheet.absoluteFillObject,
},
});
class HomeTemporary extends Component {
render() {
return (
<ScrollableTabView
renderTabBar={() => <ScrollableTabBar />}
>
<ScrollView tabLabel="List" style={styles.tabContent}>
<Text>Content Tab One</Text>
</ScrollView>
<ScrollView tabLabel="Map" style={styles.tabContent}>
<MapView
scrollEnabled
style={styles.map}
provider={MapView.PROVIDER_GOOGLE}
initialRegion={{
latitude: 25.2048493,
longitude: 55.2707828,
latitudeDelta: LATITUDE_DELTA,
longitudeDelta: LONGITUDE_DELTA,
}}
/>
</ScrollView>
</ScrollableTabView>
);
}
}
Absolutely about what? If the map inside the view, the view component must also specify the absolute value of the width and height. In your case for tabContent.

How to get full screen background with a transparent statusbar?

I want to show a react-native-maps in full screen. But the header of the StackNavigator (react native navigation) should be shown over the map. The status bar too. I want to add a small gradient over the map to make the status bar and back button (and maybe more buttons on the right header side) more readable.
At the moment the use of the StackNavigator automatically limiting the "fullscreen" map (flex: 1) to the bottom of the navigation header.
How to solve this?
react-native: 0.46
react-navigation: 1.0.0-beta.11
For those who want to solve this, just add the following to your screen-component:
static navigationOptions = {
headerStyle: {
position: 'absolute',
top: 0,
left: 0
},
headerBackTitleStyle: {
opacity: 0,
},
headerTintColor: '#fff'
};
And add some LinearGradients (if you want) and you have something like this:
Just Use React-Native StatusBar API
<View style={styles.container}>
<StatusBar backgroundColor={Color.TRANSPARENT} translucent={true} />
<MapView
provider={PROVIDER_GOOGLE} // remove if not using Google Maps
style={styles.map}
region={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.015,
longitudeDelta: 0.0121,
}}
/>
</View>

react-native-maps marker throwing and IndexOutofBoundsException: Invalid index 1, size is 0

I'm trying to get a react-native-maps Marker to show up on my Android device (it work's perfectly fine on iOS) but it's throwing me an IndexOutofBoundsException: Invalid index 1, size is 0 error at render time.
http://i.imgur.com/owletnw.png
render() {
const INITIAL_REGION = { latitude: 52.221835, longitude: 21.000896, latitudeDelta: 0.0922, longitudeDelta: 0.0421 };
return (
<MapView ref="map"
showsUserLocation = { true }
loadingEnabled = { true }
showsTraffic = { false }
showsBuildings = { false }
style = { styles.map, {flex: 1} }
initialRegion = { INITIAL_REGION }
>
<View style={{flex: 0.1, flexDirection: 'row', position: 'absolute', justifyContent: 'space-between', backgroundColor: 'transparent'}}>
<Button onPress={() => this.showWithinRadius(5)}>Wszystkie ~5km</Button>
<Button onPress={() => this.showWithinRadius(10)}>Wszystkie ~10km</Button>
<Button onPress={() => this.showWithinRadius(15)}>Wszystkie ~15km</Button>
<Button onPress={() => this.showAllOffers()}>Wszystkie oferty</Button>
</View>
{ console.log(this.state.offerLocation) }
<Marker
coordinate = { {latitude: 52.259216308593, longitude: 21.041564941406} }
title = { this.props.selectedOffer.offer.title }
/>
</MapView>
);
}
Any idea what could be causing this behaviour? I've tried deleting the View block from the MapView component but that doesn't seem to help. In the actual app I'm planning to pass the coordinates by an object which seem to works in the fitToCoordinates method.
No solutions were given to this issue but it helped me understand and fix mine.
I don't think the View is the problem but the order in which the components are rendered.
It seems like, on Android, render order matters.
So, rendering Markers as first child of MapView fixed it for me.
It is also mentioned here :
https://github.com/react-community/react-native-maps/issues/291
Hope I'm helping !
Nevermind, it was in fact the View component inside the MapView that was causing the issue.
Put the inner View and the market inside one View, this will solve the problem.
For me, the solution was removing any view from (can be a view, an image, etc).
It had no connection to the object neither to the order.

How do I drop a pin at location on React Native MapView press?

https://facebook.github.io/react-native/docs/mapview.html
I am looking for an example on how to press on the map to create an annotation that location.
I know how to add the annotation, but do not know how to get the coordinates of where I just pressed.
I can't see anything about an onPress event in the react-native MapView docs or code - But found this on github: https://github.com/lelandrichardson/react-native-maps - looks pretty good and has an onPress event which returns the coordinates (https://github.com/lelandrichardson/react-native-maps#mapview-events)
Hope this helps!
Have a look into Gesture Responder System docs.
The easiest way is to wrap something into for example <TouchableOpacity /> and you can grab the coordinates in the onPress event handler:
<TouchableOpacity onPress={(event) => console.log(event.nativeEvent.locationX)}>
{/* ... */}
</TouchableOpacity>
Everything is quite nicely explained in the docs above, for more advanced gestures handling look into PanResponder.
I use the onPress method on the MapView like this:
class DefaultMarkers extends React.Component {
constructor(props) {
super(props);
this.state = {
markers: [],
};
}
onMapPress(e) {
this.setState({
markers: [
...this.state.markers,
{
coordinate: e.nativeEvent.coordinate,
key: id++,
},
],
}
);
}
render() {
return (
<View style={styles.container}>
<MapView
style={styles.map}
onPress={e => this.onMapPress(e)}
>
{this.state.markers.map(marker => (
<Marker
key={marker.key}
coordinate={marker.coordinate}
/>
))}
</MapView>
</View>
);
}
}
Check out the full example full example on the react-native-maps github