onUserLocationChange changes React Native Maps region
Asked Answered
E

3

6

I'm using MapView from 'react-native-maps'

I can't get the "showsMyLocationButton" to show, so I'm implementing my own.

I want do this without using React Native's geolocation because I find it to be slower than react-native-maps prop showsUserLocation. I use onUserLocationChange event which returns the coordinates. However when firing the onUserLocationChange event and setting a state which contains the userLocation, it automatically updates the region without me explicitly asking for it.

This is my code:

display_my_location(coordinate){
  alert("region changed")
  this.setState({
    region: {
      latitude: coordinate.latitude,
      longitude: coordinate.longitude,
      latitudeDelta: 0.004,
      longitudeDelta: 0.004
    },
  });
}

setUserLocation(coordinate){
  //alert("User location changed MAP SHOULDNT MOVE")
  this.setState({
    userLocation: {
      latitude: coordinate.latitude,
      longitude: coordinate.longitude,
      latitudeDelta: 0.004,
      longitudeDelta: 0.004
    }
  })
}

<MapView
      style={styles.map}
      showsMyLocationButton={true}
      onUserLocationChange={locationChangedResult => this.setUserLocation(locationChangedResult.nativeEvent.coordinate)}
      initialRegion={this.state.region_amon}
      showsUserLocation={true}
      region={this.state.region}
      mapType={this.state.map_style}
      showsCompass = {true}
      showsMyLocationButton={true}
      chacheEnabled={false}
      zoomEnabled={true}
Eucken answered 22/8, 2018 at 22:34 Comment(0)
J
2

I believe you can fix this by deleting the region prop from the MapView altogether. If you need to have the map's bounding box change programmatically you can attach a ref to the map and update in componentDidUpdate using the appropriate MapView method here:

https://github.com/react-community/react-native-maps/blob/master/docs/mapview.md#methods

Jordain answered 31/8, 2018 at 3:15 Comment(1)
I don't have region prop in MapView and the problem still exist.Kitty
D
1

I have a workaround for the above issue, we can have a custom icon on the map. After clicking on the custom icon trigger a method. In the method get the current location coordinates using Geolocation and fire animateToRegion and pass the coordinates.

Step 1: Declare mapRef

const mapRef = useRef(null);

Step 2: Assing mapRef to MapView

<View style={{flex: 1}>
<MapView
       ref={mapRef}
       ...........
 />
<TouchableOpacity
  onPress={currentLocationHandler}>
  <MaterialIcons
    name="my-location"
    size={24}
    color="black"
  />
</TouchableOpacity>
</View>

Step 3: currentLocationHandler method

const currentLocationHandler = () => {
<!-- Get location coordinates using GeoLocation npm package -->
    let currentRegion = {
      latitude: latitude from geolocation,
      longitude: longitude from geolocation,
      latitudeDelta: 0.001,
      longitudeDelta: 0.001,
    };
    mapRef.current.animateToRegion(currentRegion, 3 * 1000);
}

I hope the above steps help you to solve the issue

Devisor answered 8/12, 2021 at 13:24 Comment(0)
C
1

The question explicitly states that GeoLocation module not to be used. I have the following answer which does not use GeoLocation but just MapView.

Step 1

You need to keep mutable references to map and user's location as follows:

// we need this to manipulate the map object
const mapRef = useRef<MapView>(null);

// this variable keeps current location of the user. Once the location changes the map
// updates it using a call back
const userCurrentLocation = useRef<LatLng>();

Step 2

In your render function render the map. I have a separate call to render the map and possibly markers as follows:

// This function renders the map and the children markers
const renderMap = ({ children }: MarkersProps, region: Region) => {
    return (
        <MapView
            initialRegion={region}
            ref={mapRef}
            style={styles.map}
            provider={PROVIDER_GOOGLE}
            showsUserLocation={true}
            showsMyLocationButton={false}
            showsScale={true}
            zoomTapEnabled={true}
            maxZoomLevel={17}
            minZoomLevel={12}
            onMapReady={onMapReady}
            onRegionChangeComplete={onRegionChangeComplete}
            onLayout={(event) => onLayout(event)}
            onUserLocationChange={(event) => { userCurrentLocation.current = event.nativeEvent.coordinate }}>
            {children}
        </MapView>
    );
};

Note that userCurrentLocation reference is updated when user location changes. This would be continously updated by the MapView if user moves all the time. I believe that you must have showsUserLocation set to true for this to work.

Step 3

Place a button/icon/element for user to press to pan to where the current user location is. How you design that is irrelevant to this solution. All you need to do is to place a call back for onPress event as follows:

<CurrentPositionButton getToCurrentPosition={function (): void {
    if (!userCurrentLocation.current)
        return;
    // set the bounds center to where the user location is and use Redux geoState distance
    // to find the region to pan to
    mapRef.current?.animateToRegion (getRegion(userCurrentLocation.current, geoState.distance),500);
}} />

In my code I have a geoState Redux state that contains distance in KM, and a function to convert userCurrentLocation and that distance to a MapView Region object. How you obtain that Region from userCurrentLocation is up to you. I just copied my code here for completeness.

You must not use the userCurrentLocation in rendering logic, because as per documentation it can lead to unpredictable results.

Cristicristian answered 23/8, 2024 at 15:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.