Skip to content

feat(Viewport): per-gesture transitionsToIdleUponUserInteraction - #4364

Merged
mfazekas merged 1 commit into
mainfrom
feat/viewport-idle-per-gesture
Oct 24, 2026
Merged

mfazekas merged 1 commit into
mainfrom
feat/viewport-idle-per-gesture

Conversation

@mfazekas

@mfazekas mfazekas commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #3115

Viewport's transitionsToIdleUponUserInteraction now also accepts an object, so following can stop on a pan but keep going through zoom, rotate and pitch:

<Viewport transitionsToIdleUponUserInteraction={{ pan: true, pinch: false, doubleTap: false, rotate: false, pitch: false }} />

Keys are pan, pinch (also quick zoom), doubleTap (also two-finger tap zoom out), rotate and pitch. Omitted keys default to true. The boolean form is unchanged.

With the object form, native turns the SDK's own option off and calls viewport.idle() when a gesture whose key is true begins. The status event still reports UserInteraction as the reason.

  • iOS uses GestureManagerDelegate.didBegin. For idling gestures it also cancels camera animations, as the SDK option does on touch.
  • Android uses the move/scale/rotate/shove begin listeners. There is no double-tap listener, but the SDK's double-tap and two-finger-tap zoom call onScaleBegin without starting the scale detector. A scale begin is therefore classified on the next main-loop turn: pinch if the scale detector is in progress by then, otherwise double tap. When pinch and doubleTap have the same value, no classification is needed and it is handled immediately.

While in a followPuck state, a zoom, rotate or pitch gesture that doesn't idle clears the live state's zoom, bearing or pitch, so the user's value sticks. The next transitionTo applies the requested values again.

Focal point: while following with pinch or doubleTap not idling, the gesture focal point is set to the puck's screen position (the padded viewport centre) and kept updated on camera changes. Pinch-pan is also turned off, which stops a drifting two-finger pinch from beginning a pan. iOS uses focalPoint/pinchPanEnabled in points; Android uses focalPoint/pinchScrollEnabled, where cameraState.padding and the view size are already in pixels. Both are restored when following ends. Neither is touched if the app already set a focal point or gestureSettings.pinchPanEnabled. If the focal point changes under us (e.g. once #4163 lands), we stop managing it, so the app's value wins.

Unmounting <Viewport> removes the gesture listeners and restores the focal point and pinch-pan. Like the boolean prop on main, it leaves the SDK option itself as last set. That is being fixed separately (the "prop stays on the map after unmount" fix). The two changes touch neighbouring code in RNMBXViewport on both platforms, so whichever lands second may need a small rebase. Camera followUserLocation is unchanged.

Verified on an iOS 26.5 simulator and an Android 14 emulator, on main and then on this branch, following a simulated location moving at about 15 m/s (new example: Camera > Viewport Gestures):

  1. true/false behave as on main on both platforms. With true: pan idles; iOS pure pinch keeps following; Android double-tap idles. With false: pan and zoom are overwritten by the follow state.
  2. { pan: true }: a pan idles immediately and the map pans (both). iOS pinch and double-tap keep following, stay centred on the puck, and the zoom sticks (16 → 16.56 → 17.56). Android double-tap keeps following and centred and sticks at 17. Re-following restores zoom 16 (Android).
  3. iOS rotate keeps following and the bearing sticks.
  4. Android { pan: false, pinch: false, doubleTap: true }: double-tap idles and pan keeps following, which exercises the double-tap classification.
  5. After following ends, the focal point is restored: an off-centre pinch (iOS) or double-tap (Android) zooms around the fingers, not the centre.

Not verified:

  • Android pinch, rotate, pitch and two-finger tap: multi-touch can't be injected on the emulator.
  • Pitch on iOS: the simulator's synthesized two-finger drag didn't trigger pitch.
  • iOS two-finger tap.
  • Physical devices.

Open questions:

  1. Should the focal-point/pinch-pan override stay automatic, or become opt-in?
  2. Should Camera followUserLocation get the same option?
  3. Android's double-tap inference relies on the SDK calling onScaleBegin from its double-tap animation, which is internal behaviour of maps-android 11.x.

Checklist

  • I've read CONTRIBUTING.md
  • I updated the doc/other generated code with running yarn generate in the root folder
  • I have tested the new feature on /example app.
    • In V11 mode/ios
    • In New Architecture mode/ios
    • In V11 mode/android
    • In New Architecture mode/android
  • I added/updated a sample - if a new feature was implemented (/example)

Screenshot OR Video

iOS, { pan: true } and the rest kept: follow, then an off-centre pinch (zoom 16.56), still 16.56 four seconds later, then a double-tap (17.56). Still following, with the puck centred.

ios-object-pinch-doubletap

Android, same config: double-tap (17), still 17 four seconds later, re-follow restores 16, then a pan idles with UserInteraction.

android-object-doubletap-refollow-pan

iOS: a swipe while following with true (left) and with the object form (right). Both idle and pan the map.

ios-pan-true-vs-object

Component to reproduce the issue you're fixing

See example/src/examples/Camera/ViewportGestures.tsx.

transitionsToIdleUponUserInteraction now also accepts an object of
gestures (pan, pinch, doubleTap, rotate, pitch), so following can stop
on a pan but continue through zoom, rotate and pitch. Omitted keys
default to true; the boolean form is unchanged.

With the object form, the SDK option is turned off and the viewport
is idled from the typed gesture-begin callbacks. While following, a
zoom/rotate/pitch gesture that doesn't idle clears the follow state's
zoom/bearing/pitch so the user's value sticks, and zoom gestures are
anchored on the puck via the gesture focal point.

Fixes #3115
@mfazekas
mfazekas force-pushed the feat/viewport-idle-per-gesture branch from 4acb395 to 9ed4eff Compare October 23, 2026 20:48
@mfazekas
mfazekas marked this pull request as ready for review October 24, 2026 05:15
@mfazekas
mfazekas merged commit dc41695 into main Oct 24, 2026
10 checks passed
@mfazekas
mfazekas deleted the feat/viewport-idle-per-gesture branch October 24, 2026 05:16

This branch was previously deployed

1 inactive deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Follow user location is lost when zooming the map in/out

1 participant