ScrollArea: pointer.delta() in the first frame of a new drag equals `new_DOWN_pos - old_UP_pos`, causing scroll jump on touch after fling
- Dominant language
- Rust
- Stars
- 30.6k
- Forks
- 2.1k
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 72
Description
### Platform
- **Device:** Xiaomi MIUI, Android 14
- **egui version:** 0.31 (via `[patch.crates-io]` in our project)
- **Architecture:** egui through NativeActivity (android-activity), without eframe, only `egui_glow`
- **Input:** touch only (MotionEvent from Android NDK), no mouse
### Description
Using `ScrollArea` with `drag_to_scroll(true)` on a touch screen:
1. User swipes up — fling (kinetic scrolling) starts
2. Fling stops
3. User touches the screen at a lower position
4. **Result:** content instantly jumps 100-200pt downward
### Root cause
In `PointerState::begin_pass()` the delta is computed as the difference between `latest_pos` after event processing and `old_pos` (which equals `latest_pos` before processing):
```rust
self.delta = if let (Some(old_pos), Some(new_pos)) = (old_pos, self.latest_pos) {
new_pos - old_pos // old_pos from previous UP, new_pos from new DOWN
} else {
Vec2::ZERO
};
```
On the first frame of a new drag:
- `old_pos = Some(pos_from_UP)` — last position from the previous gesture
- `self.latest_pos = Some(pos_of_new_DOWN)` — set when processing `PointerButton { pressed: true }`
- `delta = pos_of_new_DOWN - pos_from_UP` — can be 100-200pt
ScrollArea applies this delta via `state.offset -= pointer.delta()`, causing an instant jump.
### Fix (2 changes in egui + batching in backend)
#### 1. `input_state/mod.rs` — reset `old_pos` on `PointerButton { pressed: true }`
```diff
if pressed {
+ old_pos = Some(pos); // reset old_pos so pointer.delta() is zero
self.pos_history.clear();
}
```
#### 2. `containers/scroll_area.rs` — reset `state.vel` and `smooth_scroll_delta` at `drag_started()`
#### 3. Backend batching — only `PointerButton { pressed: true }` enters the frame on DOWN; all Move events are deferred
### References to our fork
- **Commit with the patch:** https://github.com/toffeantyri/egui-android-framework/tree/cb4debc
- **PATCH_NOTES.md (Russian):** https://github.com/toffeantyri/egui-android-framework/blob/main/patches/egui/PATCH_NOTES.md
- **Reproduction screen:** "Modifier Value" in our `examples/showcase`
### Files to patch in egui
- `crates/egui/src/input_state/mod.rs` — `PointerState::begin_pass()`, lines ~951-955
- `crates/egui/src/containers/scroll_area.rs` — `drag_started()` block, lines ~642-646
Contributor guide
Research direction
Start in crates/egui/src/input_state/mod.rs at PointerState::begin_pass() and inspect the PointerButton press handling, then review the drag_started() block in crates/egui/src/containers/scroll_area.rs. Reproduce the touch-after-fling case using the reported Modifier Value showcase and check the Android backend’s MotionEvent batching. Done means a new touch does not jump and starts without stale scroll velocity or smooth-scroll delta.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- frontend, mobile-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100