You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, BouncingScrollPhysics in Flutter uses a single SpringDescription for both momentum scrolling (flings) and the overscroll recovery (snap-back/rubber band effect).
This design forces a compromise:
If we tune the spring for a natural scroll feel, the snap-back becomes too loose and "floaty" compared to native iOS.
If we tune it for a snappy return, the scrolling becomes too stiff.
As a result, Flutter's iOS scroll feel lacks the characteristic "heavy and snappy" rubber band effect found in UIScrollView, creating an "uncanny valley" effect for users.
Video
online-video-cutter.com.mp4
Describe the solution
Native iOS behaves as if it uses a different physical property when snapping back from an overscroll. Flutter should implement a dedicated spring simulation for this specific phase.
I have analyzed the motion curves of native iOS and found that separating the spring logic significantly improves fidelity.
Proposed Logic:
Keep the existing spring for standard scrolling to maintain smoothness.
Apply a specific "Rubber Band Spring" when the scroll position is out of bounds and the gesture ends.
Empirically tuned values for this spring: mass: 1.0, stiffness: 1e5 * lambda^2, damping: 100001 * lambda.
Note
The constants were specially tuned to achieve exponential damping for the spring.
Additional context
I have measured and compared the scroll position over time between:
Native iOS (UIScrollView)
Current Flutter
New Flutter implementation
As shown in the graph, the current Flutter implementation (Cyan) exhibits a significantly slower recovery compared to native iOS. It lacks the initial 'snap' (stiffness) and takes considerably longer to settle (~0.81s) compared to the native duration (~0.63s), leading to the perceived "floaty" behavior.
In contrast, the new implementation (Brown) closely aligns with the native curve (Blue) in trajectory.
Currently,
BouncingScrollPhysicsin Flutter uses a singleSpringDescriptionfor both momentum scrolling (flings) and the overscroll recovery (snap-back/rubber band effect).This design forces a compromise:
As a result, Flutter's iOS scroll feel lacks the characteristic "heavy and snappy" rubber band effect found in
UIScrollView, creating an "uncanny valley" effect for users.Video
online-video-cutter.com.mp4
Describe the solution
Native iOS behaves as if it uses a different physical property when snapping back from an overscroll. Flutter should implement a dedicated spring simulation for this specific phase.
I have analyzed the motion curves of native iOS and found that separating the spring logic significantly improves fidelity.
Proposed Logic:
mass: 1.0,stiffness: 1e5 * lambda^2,damping: 100001 * lambda.Note
The constants were specially tuned to achieve exponential damping for the spring.
Additional context
I have measured and compared the scroll position over time between:
As shown in the graph, the current Flutter implementation (Cyan) exhibits a significantly slower recovery compared to native iOS. It lacks the initial 'snap' (stiffness) and takes considerably longer to settle (~0.81s) compared to the native duration (~0.63s), leading to the perceived "floaty" behavior.
In contrast, the new implementation (Brown) closely aligns with the native curve (Blue) in trajectory.
I have a PR ready with this fix.