mapbox / mapbox/mapbox-maps-android

[gestures] Native fling ignores moderate pans and has no API to tune OverScroller friction

Open
#2,729 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug :beetle:
Dominant language
Kotlin
Stars
578
Forks
161
PR merge metrics
No merged PRs in 30d

Description

Not sure if this is intended from the library or a bug.

## Environment

- Android OS version: All versions tested (SDK-level; not device-specific)
- Devices affected: All Android devices. Compared against iOS Maps SDK, where pan lift-off glides with `UIScrollView.DecelerationRate.normal`.
- Maps SDK Version: 11.27.0 (also present on 11.25+ where `useNativeFlingDeceleration` shipped; still no public knobs in 11.28)

## Observed behavior and steps to reproduce

1. Show a `MapView` with globe or mercator projection.
2. Enable native fling:

```kotlin
mapView.gestures.updateSettings {
scrollDecelerationEnabled = true
useNativeFlingDeceleration = true
}
```

3. Pan the map, then lift the finger.

**Without** `useNativeFlingDeceleration`: the map stops immediately on lift (legacy `easeTo`).

**With** it enabled (default still `false`):

- Fast flicks get some momentum, but it dies faster than iOS / Google Maps. `OverScroller` uses list-scroll friction (`ViewConfiguration.getScrollFriction()` ≈ `0.015`).
- Moderate / follow-through pans (density-normalized velocity ~300–1000) get **no** fling. The map hard-stops. `VELOCITY_THRESHOLD_IGNORE_FLING` is still inlined at `1000` ([PR #599](https://github.com/mapbox/mapbox-maps-android/pull/599)).

There is no public `GesturesSettings` field for friction or that threshold. Matching iOS today requires reflecting into `overScrollerFlingAnimator` / `overScroller` and wrapping `onFling`.

## Expected behavior

After a pan, lift-off should continue with physics-based deceleration, including moderate pans, similar to iOS `panDecelerationFactor` (~`0.998` / `UIScrollView.DecelerationRate.normal`).

Please either:

1. Expose `OverScroller` friction (and/or a map-appropriate default lower than `0.015`).
2. Lower or make configurable `VELOCITY_THRESHOLD_IGNORE_FLING` (Mapbox 9.5 / MapLibre used ~300).
3. Document that `useNativeFlingDeceleration` is required for any iOS-like glide, and that it is still `false` by default.

## Notes / preliminary analysis

`useNativeFlingDeceleration` in 11.25 replaced `easeTo` with `OverScroller`, which is the right direction, but two internals still make lift-off feel sticky:

1. **Friction.** Default `OverScroller` friction is for `ListView`, not a map. Lowering it to ~`0.006` via reflection gets much closer to iOS.
2. **Velocity gate.** `onFling` returns false below 1000, so `OverScroller` never starts for typical “drag then lift” gestures. Forcing `fling()` in the 300–1000 band restores those.

11.27’s “fling animation moving the camera in the opposite direction at low zoom” fix is separate and works. This is leftover physics, not that globe-direction bug.

Workaround we are using (fragile; depends on private fields):

- `useNativeFlingDeceleration = true`
- `overScroller.setFriction(0.006f)` via reflection
- If stock `onFling` returns false and `hypot(vx/density, vy/density)` is in `[300, 1000)`, call the internal animator `fling()` ourselves

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the native fling path through GesturesSettings, onFling, overScrollerFlingAnimator, and OverScroller, focusing on the 1000 velocity gate and default friction. Compare behavior for fast and moderate pans, then determine which requested resolution is appropriate: configurable friction or threshold, a changed default, or documentation. Done means the selected behavior is covered and the public API or documentation accurately describes it.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.