Build map guidance that follows the user without blocking pinch-to-zoom
A navigation map should help the user move through the world, not fight every gesture they make. I recently hit a deceptively simple bug while building field guidance in a React Native / Expo app: the route rendered correctly and the camera followed the current position, but users could not meaningfully zoom or pan while walking. They could pinch the map, but the next location update snapped the camera back to a fixed zoom. The map looked active. The experience felt broken. The cause: two camera owners The implementation combined two useful features: - followsUserLocation={true} on the native map. - animateCamera(...) after every location update, using a fixed walking zoom and pitch. Each feature was reasonable on its own. Together, they gave the camera two automatic owners and the user none. A pinch gesture changed the zoom for a fraction of a second. Then a GPS update arrived and our effect applied the navigation camera again. On iOS, native user-follow behavior added another layer of camera control. A better model: follow mode and explore mode The fix was not to stop navigation. Route progress, distance, bearing, breadcrumb recording and off-route detection should all continue regardless of what the user does with the map. Only the camera behavior should change. We now keep a small piece of local UI state: const [cameraFollowing, setCameraFollowing] = useState(navigationActive); useEffect(() => { if (!navigationActive || !cameraFollowing || bearing == null) return; mapRef.current?.animateCamera( walkingCamera(currentCoordinate, bearing), { duration: 480 }, ); }, [currentCoordinate, bearing, navigationActive, cameraFollowing]); The native follow prop uses the same state: { if (navigationActive) setCameraFollowing(false); }} /> As soon as the user touches the map, the camera enters explore mode. Pinch, pan and rotation work normally. The active route and navigation calculations continue in the background. A large location button restores follow mode: function recenterAndFollow() { setCameraFollowing(true); mapRef.current?.animateCamera( walkingCamera(currentCoordinate, bearing), { duration: 420 }, ); } This creates a familiar contract: - start guidance: follow automatically; - touch the map: inspect freely; - tap the location arrow: resume following; - stop guidance: return to the ordinary overview map. Why onTouchStart? react-native-maps exposes gesture details on region-change events, but isGesture is not equally available across providers. Relying only on that detail can produce different behavior between Google Maps and Apple Maps. For this field use case, a touch is a good expression of intent: the user wants control of the map. The action is reversible with one obvious button. Keep navigation state separate from presentation state The most important architectural lesson is that camera state is not navigation state. These should continue while the camera is detached: - current-position updates; - remaining route distance; - bearing and direction; - off-route detection; - route recalculation; - local breadcrumb recording. Only camera animations are suspended. That separation prevents a UI gesture from accidentally stopping the trip or discarding route progress. Outdoor UX details that matter Field navigation is used with cold fingers, sunlight, rain and intermittent attention. A few details made the interaction clearer: - a 52-point recenter button with a generous hit area; - high-contrast route colors; - route status outside the map, so it is still readable while zooming; - no hidden gesture required to resume following; - tests that assert both map surfaces use the same follow/explore contract. We applied this pattern to both live trip guidance and navigation back to a privately saved place. Consistency matters: users should not have to learn two camera behaviors inside the same app. The product context I found this issue while developing Mycoverse, an iPhone app for planning mushroom trips with weather, habitat and seasonal signals, plus a private field journal. Exact saved places are private by default. The app does not identify mushrooms, guarantee a find or provide food-safety advice. The bug came from real field feedback, which is exactly the kind of feedback a simulator rarely produces. If your app guides people outdoors, test it while walking, locking the phone, putting it in a pocket, resuming it and trying to inspect the map mid-route. That is where the real interface begins. Top comments (0)
Comments
No comments yet. Start the discussion.