react native maps: center marker onPress before Callout is displayed
Asked Answered
I

2

8

When a user presses on a marker I am calling animateToCoordinate to center the marker in the middle of the screen. The problem is that the callout is rendered to the position of the region before animateToCoordinate is done its animation so the callout is displayed somewhat offscreen. is there anyway to delay callout display until animateToRegion is finished? Or is there another way to go about this entirely that I am not seeing?

 <MapView
    ref = {(mapView) => { _mapView = mapView; }}
    style={styles.map} 
    region={this.state.mapRegion}
    showsUserLocation = {true}
    showsMyLocationButton   = {true}
    followUserLocation={true}
    onRegionChange={this.onRegionChange.bind(this)}>


 {data.near.map(marker => 
   {if(marker.posts.length != 0){
     return (
      <MapView.Marker
      coordinate={{latitude: marker.location.latitude,
            longitude: marker.location.longitude}}
      title={marker.name}
      description={marker.description}
      onPress={ e => _mapView.animateToCoordinate({
        latitude: e.nativeEvent.coordinate.latitude,
        longitude:  e.nativeEvent.coordinate.longitude
      }, 500)}
      onCalloutPress={ e => this._onPressItem(marker.id)}
    >
    <Icon name="ios-pin" style={{ fontSize: 45, color: '#f04c34'}} />

    <MapView.Callout 
            style={{ flex: -1, position: 'absolute', width: width}}>
    <ListItem >

    <Body >
        <View style={{flex: 1,
        flexDirection: 'row',
        justifyContent: 'space-between',}}>
    <Text style={{fontSize: 18, color: '#38383a', marginBottom: 10, fontWeight: 'bold'}} 
    >{marker.name}</Text>

    <Text style={{fontSize: 14, color: '#38383a', fontWeight: 'bold'}}>{marker.distance.toFixed(2)} miles</Text>
</View>
    <Text style={{fontSize: 16,  fontFamily: 'Avenir', marginBottom: 15}}
    >{marker.infoText}</Text>

    <Text>
    <Text style={{fontSize: 12, color: '#38383a', fontWeight: 'bold'}}
    >{marker.address}</Text>

    </Text>

        </Body>
        <Right></Right>




</ListItem>
  </MapView.Callout>
    </MapView.Marker>
     )
   }else return null;

   })}
  </MapView>
Infundibuliform answered 16/9, 2017 at 4:28 Comment(1)
Did you ever figure out a way to do this? I'm trying to do the same thing.Weaponless
J
2

I am having this precise issue as well. My current solution is to make my marker's onPress look something like this:

markerOnPress (coord) {
  TIME_FOR_ANIMATION = 700;
  this.mapview.animateToCoordinate(coord);
  setTimeout(() => {
    this.markerRef.showCallout();
  }, TIME_FOR_ANIMATION);
}

And my marker looks like this:

<Marker
  ref={(ref) => { this.markerRef = ref; }}
  coordinate={coord}
  title={someTitle}
  description={someDescription}
  onPress={() => this.onMarkerPress(coord)}
/>

This works alright, although there is some unwanted behavior still occurring and I'm not sure why. Now when I click on a marker, the callout appears immediately, then disappears before animating to the coordinate, animates to the coordinate, and then displays the callout as desired. I have no idea why it's still immediately displaying the callout initially. I tried fixing this by making the first line of markerOnPress this.markerRef.hideCallout() but this had no noticeable effect.

Judaea answered 13/7, 2018 at 16:5 Comment(1)
For me this solution makes the callout briefly appear when it should before immediately disappearing, moving to a completely different pin and making its callout appear. Not sure if this is just improper implementation on my end, but nevertheless unfortunately the only GitHub issue for this was dismissed for an improper template.Vignola
S
0

I found a make shift way to address this...

Using a state variable, you can hide/show a blank callout and the callout you want to show

{this.state.showCallout == true ? <Callout tooltip={true}>
    <View style={{backgroundColor: 'white', width: 'auto', minWidth: 50, paddingVertical: 2}}>
        {emp.type == "group" ?
        <View>
            {emp.employees.map(e => {
                return (
                    <Text style={{marginVertical: 2}}>{e.display_name}</Text>
                )
            })}
        </View>
        : 
        <Text>
        
        </Text>}
    </View>
</Callout> : <Callout tooltip={true}>
    <View style={{backgroundColor: 'transparent'}}></View>
</Callout>}

Then in onPress, you can setTimeout

this.mapRef.animateCamera({
    center: {
        latitude: emp.latitude,
        longitude: emp.longitude,
    },
    heading: 0, pitch: 0, 
    zoom: 32,
    altitude: 1000,
}, {duration: 1000});
setTimeout(() => {
    this.setState({ showCallout: true })
    this.markerRefs[i].showCallout();
},1000)

Then in onCalloutPress you can do

this.markersRefs[i].hideCallout();
this.setState({ showCallout: false )};
Stovall answered 1/12, 2021 at 23:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.