I'd like to use OpenStreetMap tiles in my React Native app on Android, so I'm trying to wrap the OSMDroid native UI component as described here. For the most part it's working fine, but I'm having trouble figuring out how to correctly handle events, specifically onScroll
and onZoom
.
With OSMDroid, you set a DelayedMapListener to handle the events, which is pretty straightforward. I've confirmed that events are being handle correctly Java-side up until the point where the JS code should be triggered. However, they're not triggering my JavaScript code.
Based on the documentation, I've implemented the event handlers in Java in the createViewInstance
method of my view manager:
map.setMapListener(new DelayedMapListener(new MapListener() {
public boolean onScroll(ScrollEvent event) {
WritableMap eventData = Arguments.createMap();
// Fill in eventData; details not important
ReactContext reactContext = (ReactContext)map.getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
map.getId(),
"topChange",
eventData);
return true;
}
public boolean onZoom(ZoomEvent event) {
// Basically the same as above
}
}, 100));
The relevant part of my JS code is basically identical to the code in the documentation linked above:
class OSMDroidMapView extends Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
_onChange(event: Event) {
console.log(event);
// Handle event data
}
render() {
return <OSMDroidMapView {...this.props} onChange={this._onChange}/>
}
}
There are no errors or any signs that anything is wrong. The Java event handler code is called correctly. There's just no sign of anything happening in the JS code when an event occurs. Does anyone know how to do this correctly? I feel like I must be missing some basic concept here.
To send custom events to Javascript you can use RCTDeviceEventEmitter:
In the Native side:
import com.facebook.react.modules.core.DeviceEventManagerModule;
...
public boolean onScroll(ScrollEvent event) {
WritableMap eventData = Arguments.createMap();
// Fill in eventData; details not important
ReactContext reactContext = (ReactContext)map.getContext();
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("YouCustomEventName", eventData);
return true;
}
Inside your JS module you just have to register a listener using DeviceEventEmitter:
class OSMDroidMapView extends Component {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
componentWillMount() {
DeviceEventEmitter.addListener('YouCustomEventName', this._onChange);
}
componentWillUnmount() {
DeviceEventEmitter.removeListener('YouCustomEventName', this._onChange);
}
_onChange(event: Event) {
console.log(event);
// Handle event data
}
render() {
return <OSMDroidMapView {...this.props} onChange={this._onChange}/>
}
}
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With