fix(android): MarkerView no longer blocks map pan/pinch (new arch)#4258
Open
mfazekas wants to merge 1 commit into
Open
fix(android): MarkerView no longer blocks map pan/pinch (new arch)#4258mfazekas wants to merge 1 commit into
mfazekas wants to merge 1 commit into
Conversation
mfazekas
force-pushed
the
claude/markerview-gesture-android-01b1ab
branch
from
July 20, 2026 03:33
b252a87 to
c593669
Compare
On Android with Fabric, a MarkerView captured the whole touch stream, so a pan or pinch that started on a marker never reached the map (#4255). This was a side effect of the touch fix in #4176, which called requestDisallowInterceptTouchEvent(true) on every ACTION_DOWN to keep child Pressables tappable — that also prevented the map from ever seeing the gesture (and, for pinch, the second finger's ACTION_POINTER_DOWN). Decide gesture ownership at touch-down based on what is under the finger: - Touch on a scrollable descendant (ScrollView/FlatList/ViewPager, detected via canScroll*): disallow map interception so the child keeps the gesture. The map is an ancestor and would otherwise steal the drag on its own touch slop before the child could claim it. - Otherwise: leave interception alone. Taps still reach child Pressables (Mapbox uses its own touch slop, so a tap is not intercepted) while a pan/pinch that merely starts on the marker moves the map. A tap that lands on a MarkerView is absorbed by the marker rather than falling through to touchable sources (symbol/shape layers) or pins underneath it. pointerEvents="none"/"box-none" markers stay transparent as before. Children that handle drags purely in JS (PanResponder, e.g. some sliders) never claim the native gesture and can be taken over by the map. For those, add a `stopGesturePropagation` prop: when set, the marker keeps every gesture. It is Android-only (iOS gesture recognisers already coexist with marker content).
mfazekas
force-pushed
the
claude/markerview-gesture-android-01b1ab
branch
from
July 20, 2026 06:28
c593669 to
b12d6e3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #4255
On Android with the new architecture (Fabric), a
MarkerViewblocks map pan/pinch: a gesture that starts on a marker never reaches the map, so the marker acts as a dead zone. iOS is unaffected.Root cause: a side effect of the touch fix in #4176, which called
requestDisallowInterceptTouchEvent(true)on everyACTION_DOWNto keep childPressables tappable. That also stopped the map from ever seeing the gesture — and, for pinch, from seeing the second finger'sACTION_POINTER_DOWN.Fix — decide gesture ownership at touch-down from what's under the finger, instead of always grabbing:
ScrollView/FlatList/ViewPager, detected viacanScrollHorizontally/Vertically) → disallow map interception so the child keeps the gesture. The map is an ancestor and would otherwise steal the drag on its own touch-slop before the child could claim it.Pressables (Mapbox uses its own touch-slop, so a tap isn't intercepted), while a pan/pinch that merely starts on the marker moves the map.Two more things:
MarkerViewis absorbed by the marker rather than falling through to touchable sources (symbol/shape layers) or pins underneath it.pointerEvents="none"/"box-none"markers stay transparent.stopGesturePropagationprop (Android-only): children that handle drags purely in JS (PanResponder, e.g. some sliders) never claim the native gesture and can be taken over by the map — a nondeterministic race. SettingstopGesturePropagationmakes the marker keep every gesture. iOS gesture recognisers already coexist with marker content, so it's a no-op there (mirrors react-native-maps' iOS-onlystopPropagation, inverted).Ran
yarn generate(docs updated). Native + JS change; no style-spec changes.Checklist
CONTRIBUTING.mdyarn generatein the root folder/exampleapp./exampleMarker View: scrollable-in-marker, feature-under-marker, and astopGesturePropagationtoggle)Screenshot OR Video
Verified on a physical Android device (New Architecture), driving the same gestures before/after:
Pressable/counter — works; tap on marker over a feature — feature underneath is not selected; the same feature just outside the marker still is.ScrollViewinside a marker — scrolls the child, map does not pan.@rneuislider (JS PanResponder) inside a marker — races the map (nondeterministic; reproduced both a clean drag and a leak on the same slider). WithstopGesturePropagation, three consecutive slider drags never pan the map.pointerEvents="none"— tap/drag still passes through and selects the feature underneath.Pinch-zoom starting on a marker zooms the map (confirmed on device) — the marker no longer grabs on DOWN for non-scrollable content, so the map sees the whole gesture including the second finger.
Component to reproduce the issue you're fixing
Reproducer — pan-through, tap shield, scrollable, and slider opt-in
Drag on the pink marker: on the unfixed build the map doesn't move; with the fix it pans. Tapping the marker doesn't select the red circle underneath. The horizontal strip scrolls without panning the map. The
@rneuislider may occasionally hand the drag to the map — setstopGesturePropagationto make it keep the gesture every time.