You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
iOS: 17+ (tested on simulator iOS 26 and real device via TestFlight)
Provider: PROVIDER_GOOGLE on both instances
Summary
When two MapView instances with PROVIDER_GOOGLE coexist in the same view hierarchy on iOS -- a non-interactive "preview" one (scrollEnabled={false}, zoomEnabled={false}, rotateEnabled={false}, pitchEnabled={false}, pointerEvents="none") and an interactive fullscreen one inside a Modal -- all gestures (pan / zoom / tap) on the interactive one are silently blocked. onMapReady fires, tiles render, onRegionChangeComplete fires once for the initial region, but no subsequent onRegionChange, onPanDrag, or onPress events are emitted. This persists across Modal re-opens until the app is restarted.
Reproduction
Minimal repro is straightforward:
Render a screen that contains a <MapView provider={PROVIDER_GOOGLE} scrollEnabled={false} zoomEnabled={false} ... /> as a static preview.
On tap, open a Modal containing an interactive <MapView provider={PROVIDER_GOOGLE} />.
Try to pan/zoom/tap the interactive map. Nothing happens.
Remove the static preview from the screen entirely -> the interactive map works normally.
Root cause
Confirmed by Xcode View Hierarchy Debugger: both GMSMapView instances register native UIGestureRecognizer objects. Disabling gestures via scrollEnabled={false} etc. does not remove the recognizers, it only flips their enabled state. They remain in the hit-testing chain, where they interfere with the recognizers of the second GMSMapView.
Use Apple Maps (default provider, provider={undefined}) for the non-interactive preview on iOS, with cacheEnabled={true} so it renders as a cached image. Keep PROVIDER_GOOGLE for the interactive fullscreen map. This works because Apple Maps (MKMapView) and Google Maps (GMSMapView) use entirely separate gesture stacks.
// iOS: Apple Maps + cacheEnabled (static image, no gesture recognizers)// Android: Google Maps + liteMode (bitmap)<MapViewprovider={Platform.OS==='ios' ? undefined : PROVIDER_GOOGLE}scrollEnabled={false}zoomEnabled={false}rotateEnabled={false}pitchEnabled={false}liteMode={Platform.OS==='android'}cacheEnabled={Platform.OS==='ios'}pointerEvents="none"/>
What I think the library could do
Three possible directions, in rough order of preference:
Documentation warning. Add an explicit note in the README / PROVIDER_GOOGLE docs that two PROVIDER_GOOGLE instances in the same view hierarchy on iOS can break gestures, and recommend Apple Maps + cacheEnabled (or liteMode on Android) for static previews. This is the cheapest fix and immediately saves people days of debugging.
iOS equivalent of liteMode. Implement iOS liteMode via MKMapSnapshotter (Apple Maps) or via GMSMapView.takeSnapshot + replace-with-image lifecycle (Google Maps). Discussed in Feature: liteMode support on iOS via MKMapSnapshotter? #2497 and liteMode IOS #1411 but never shipped. A concrete modern use case: mobile apps that show a small map preview on a list/detail screen and open a fullscreen interactive map on tap. Without liteMode on iOS, this pattern silently breaks.
Explicit API to detach gesture recognizers. A prop like gestureRecognizersEnabled={false} that calls -[UIView removeGestureRecognizer:] on all recognizers of the underlying GMSMapView, not just flips their enabled flag. This would be more targeted than liteMode for users who want a live (not cached) static map without gesture interference.
Additional notes
This is not a regression in react-native-maps -- it's a Google SDK limitation. But the library is where developers hit it, and documenting the workaround here would be high-leverage.
The symptom is particularly confusing because the broken map still renders tiles and fires onMapReady. Developers naturally look for overlays, pointerEvents, Modal issues, etc. before suspecting a second MapView instance elsewhere on the screen.
Issue Feature: liteMode support on iOS via MKMapSnapshotter? #2497 ("Feature: liteMode support on iOS via MKMapSnapshotter") was closed 7+ years ago without resolution. Filing this fresh with a concrete repro and confirmed workaround seems more useful than commenting on a stale thread.
Environment
react-native-maps: 1.27.2PROVIDER_GOOGLEon both instancesSummary
When two
MapViewinstances withPROVIDER_GOOGLEcoexist in the same view hierarchy on iOS -- a non-interactive "preview" one (scrollEnabled={false},zoomEnabled={false},rotateEnabled={false},pitchEnabled={false},pointerEvents="none") and an interactive fullscreen one inside a Modal -- all gestures (pan / zoom / tap) on the interactive one are silently blocked.onMapReadyfires, tiles render,onRegionChangeCompletefires once for the initial region, but no subsequentonRegionChange,onPanDrag, oronPressevents are emitted. This persists across Modal re-opens until the app is restarted.Reproduction
Minimal repro is straightforward:
<MapView provider={PROVIDER_GOOGLE} scrollEnabled={false} zoomEnabled={false} ... />as a static preview.<MapView provider={PROVIDER_GOOGLE} />.Root cause
Confirmed by Xcode View Hierarchy Debugger: both
GMSMapViewinstances register nativeUIGestureRecognizerobjects. Disabling gestures viascrollEnabled={false}etc. does not remove the recognizers, it only flips theirenabledstate. They remain in the hit-testing chain, where they interfere with the recognizers of the secondGMSMapView.This is consistent with Google's own statement: "Maps SDK for iOS has not been optimized for multiple windows/instances and may result in undefined behavior." -- https://developers.google.com/maps/documentation/ios-sdk/start
Workaround (what actually works)
Use Apple Maps (default provider,
provider={undefined}) for the non-interactive preview on iOS, withcacheEnabled={true}so it renders as a cached image. KeepPROVIDER_GOOGLEfor the interactive fullscreen map. This works because Apple Maps (MKMapView) and Google Maps (GMSMapView) use entirely separate gesture stacks.What I think the library could do
Three possible directions, in rough order of preference:
Documentation warning. Add an explicit note in the README /
PROVIDER_GOOGLEdocs that twoPROVIDER_GOOGLEinstances in the same view hierarchy on iOS can break gestures, and recommend Apple Maps +cacheEnabled(orliteModeon Android) for static previews. This is the cheapest fix and immediately saves people days of debugging.iOS equivalent of
liteMode. Implement iOSliteModeviaMKMapSnapshotter(Apple Maps) or viaGMSMapView.takeSnapshot+ replace-with-image lifecycle (Google Maps). Discussed in Feature: liteMode support on iOS via MKMapSnapshotter? #2497 and liteMode IOS #1411 but never shipped. A concrete modern use case: mobile apps that show a small map preview on a list/detail screen and open a fullscreen interactive map on tap. WithoutliteModeon iOS, this pattern silently breaks.Explicit API to detach gesture recognizers. A prop like
gestureRecognizersEnabled={false}that calls-[UIView removeGestureRecognizer:]on all recognizers of the underlyingGMSMapView, not just flips theirenabledflag. This would be more targeted thanliteModefor users who want a live (not cached) static map without gesture interference.Additional notes
react-native-maps-- it's a Google SDK limitation. But the library is where developers hit it, and documenting the workaround here would be high-leverage.onMapReady. Developers naturally look for overlays,pointerEvents, Modal issues, etc. before suspecting a secondMapViewinstance elsewhere on the screen.Happy to provide a minimal repro repo if helpful.