There are two types of ScrollPhysics
that I want to apply to my ListView
. When user reaches the bottom of the List, I want BouncingScrollPhysics()
to take place, but when user reaches the top, it shouldn't bounce but rather perform ClampingScrollPhysics()
. How to achieve this?
Flutter: Make ListView bounce at the bottom and clamp at the top position
Asked Answered
Screenshot:
// create 2 instance variables
var _controller = ScrollController();
ScrollPhysics _physics = ClampingScrollPhysics();
@override
void initState() {
super.initState();
_controller.addListener(() {
if (_controller.position.pixels <= 56)
setState(() => _physics = ClampingScrollPhysics());
else
setState(() => _physics = BouncingScrollPhysics());
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
controller: _controller,
physics: _physics,
itemCount: 20,
itemBuilder: (_, i) => ListTile(title: Text("Item $i")),
),
);
}
I've just relooked at your answer and I have something to add. Before setting the state billion times you should check if the var physics is already assigned to the right one. Otherwise app may lag like crazy –
Alexiaalexin
Yes, you're right, you can use
if-else
condition to make sure you only change it when you need. For simplicity, i didn't add them. –
Neil For me the list does not scroll anymore. (I'm using pub.dev/packages/draggable_scrollbar) –
Zaibatsu
I don't wont to reload every time it change the scroll position. And I hit upon a good one. so I leave it for future readers!
_controller.addListener(() {
if (_controller.position.pixels < 0) _controller.jumpTo(0);
});
Remember that Stack Overflow isn't just intended to solve the immediate problem, but also to help future readers find solutions to similar problems, which requires understanding the underlying code. This is especially important for members of our community who are beginners, and not familiar with the syntax. Given that, can you edit your answer to include an explanation of what you're doing and why you believe it is the best approach? –
Bloodstream
oh get off it @JeremyCaney, what are you, a bot? This was helpful. –
Seavir
You can create your own custom ScrollPhysics
class :
I found one that works great, in the great modal_bottom_sheet package, source: https://github.com/jamesblasco/modal_bottom_sheet/pull/77
ListView(
physics: const BottomModalScrollPhysics(),
children: [...],
)
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class BottomModalScrollPhysics extends ScrollPhysics {
/// Creates scroll physics that prevent the scroll offset from exceeding the
/// top bound of the modal.
const BottomModalScrollPhysics({ScrollPhysics? parent})
: super(parent: parent);
@override
BottomModalScrollPhysics applyTo(ScrollPhysics? ancestor) {
return BottomModalScrollPhysics(parent: buildParent(ancestor));
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
assert(() {
if (value == position.pixels) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary(
'$runtimeType.applyBoundaryConditions() was called redundantly.'),
ErrorDescription(
'The proposed new position, $value, is exactly equal to the current position of the '
'given ${position.runtimeType}, ${position.pixels}.\n'
'The applyBoundaryConditions method should only be called when the value is '
'going to actually change the pixels, otherwise it is redundant.'),
DiagnosticsProperty<ScrollPhysics>(
'The physics object in question was', this,
style: DiagnosticsTreeStyle.errorProperty),
DiagnosticsProperty<ScrollMetrics>(
'The position object in question was', position,
style: DiagnosticsTreeStyle.errorProperty)
]);
}
return true;
}());
final direction = position.axisDirection;
// Normal vertical scroll
if (direction == AxisDirection.down) {
if (value < position.pixels &&
position.pixels <= position.minScrollExtent) {
// underscroll
return value - position.pixels;
}
if (value < position.minScrollExtent &&
position.minScrollExtent < position.pixels) {
// hit top edge
return value - position.minScrollExtent;
}
}
// Reversed vertical scroll
else if (direction == AxisDirection.up) {
if (position.maxScrollExtent <= position.pixels &&
position.pixels < value) {
// overscroll
return value - position.pixels;
}
if (position.pixels < position.maxScrollExtent &&
position.maxScrollExtent < value) {
// hit bottom edge
return value - position.maxScrollExtent;
}
}
if (parent != null) return super.applyBoundaryConditions(position, value);
return 0.0;
}
}
© 2022 - 2024 — McMap. All rights reserved.
var
for_physics
(and now updated it toScrollPhysics
) and it was causing error when assigning value to other physics, please check. – Neil