snap_scroll_physics
snap_scroll_physics copied to clipboard
CustomScrollBehavior can break snap behaviour
Hi there,
Thanks a lot for this cool package, really useful!
I found a really weird edge case where the ScrollPhysics was not behaving as expected. When I wrap a scrollable with CustomScrollBehaviour, the snapping freezes when I reach the end of the scrollable. This may only happen on web builds, I haven't tested that. I think this little video explains it much better than I could with words:
https://user-images.githubusercontent.com/31738080/217820777-7044418d-686d-4792-a9af-8307db3cbbfb.mov
If you want to test it yourself, here is the code:
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:snap_scroll_physics/snap_scroll_physics.dart';
void main() {
runApp(MyApp());
}
class CustomScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final items = List.generate(20, (index) => index);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: ScrollConfiguration(
behavior: CustomScrollBehavior(),
child: Material(
child: ListView.builder(
physics: SnapScrollPhysics(
snaps: List.generate(
items.length,
(index) => Snap(index * 120, distance: 60),
),
),
itemCount: items.length,
itemBuilder: (context, index) {
return SizedBox(
height: 120,
width: double.infinity,
child: ElevatedButton(
onPressed: () => print('pressed'),
child: Text(items[index].toString()),
),
);
},
),
),
),
);
}
}
I could also "fix" it by adding the following changes:
...
@override
Simulation? createBallisticSimulation(ScrollMetrics position,
double velocity) {
final simulation = super.createBallisticSimulation(position, velocity);
final proposedPixels = simulation?.x(double.infinity) ?? position.pixels;
final double targetUnbound =
_getTargetPixels(position, proposedPixels, this.tolerance, velocity);
final double target = targetUnbound.clamp(
position.minScrollExtent, position.maxScrollExtent);
if ((target - proposedPixels).abs() > precisionErrorTolerance) {
// if (simulation is BouncingScrollSimulation) {
// return BouncingScrollSimulation(
// leadingExtent: math.min(target, position.pixels),
// trailingExtent: math.max(target, position.pixels),
// velocity: velocity,
// position: position.pixels,
// spring: spring,
// tolerance: tolerance,
// );
// }
return ScrollSpringSimulation(
spring,
position.pixels,
target,
velocity,
tolerance: tolerance,
);
...
Cheers!