在对自己的需求进行深入分析并判断PageView
小部件的源代码后,我意识到我需要一个逐项工作的滚动小部件,但同时我需要每个项目的空间都与普通滚动条相同,因此我需要更改普通滚动条的ScrollPhysics
.在found this post中,它在某种程度上描述了Flutter 中的卷轴物理,并接近我的需求,不同之处在于我需要在当前可见小部件的两个侧面添加空间,而不仅仅是右侧.
因此,我在帖子中 Select 了CustomScrollPhysics
,并以这种方式对其进行了修改(帖子代码中更改的部分用H <--
和-->
注释表示:
class CustomScrollPhysics extends ScrollPhysics {
final double itemDimension;
const CustomScrollPhysics(
{required this.itemDimension, ScrollPhysics? parent})
: super(parent: parent);
@override
CustomScrollPhysics applyTo(ScrollPhysics? ancestor) {
return CustomScrollPhysics(
itemDimension: itemDimension, parent: buildParent(ancestor));
}
double _getPage(ScrollMetrics position, double portion) {
// <--
return (position.pixels + portion) / itemDimension;
// -->
}
double _getPixels(double page, double portion) {
// <--
return (page * itemDimension) - portion;
// -->
}
double _getTargetPixels(
ScrollMetrics position,
Tolerance tolerance,
double velocity,
double portion,
) {
// <--
double page = _getPage(position, portion);
// -->
if (velocity < -tolerance.velocity) {
page -= 0.5;
} else if (velocity > tolerance.velocity) {
page += 0.5;
}
// <--
return _getPixels(page.roundToDouble(), portion);
// -->
}
@override
Simulation? createBallisticSimulation(
ScrollMetrics position, double velocity) {
// If we're out of range and not headed back in range, defer to the parent
// ballistics, which should put us back in range at a page boundary.
if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
(velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) {
return super.createBallisticSimulation(position, velocity);
}
final Tolerance tolerance = this.tolerance;
// <--
final portion = (position.extentInside - itemDimension) / 2;
final double target =
_getTargetPixels(position, tolerance, velocity, portion);
// -->
if (target != position.pixels) {
return ScrollSpringSimulation(spring, position.pixels, target, velocity,
tolerance: tolerance);
}
return null;
}
@override
bool get allowImplicitScrolling => false;
}
总而言之,我所做的是提取当前可见小部件留下的额外空间的一半(即(position.extentInside - itemDimension) / 2
),并将其添加到基于滚动位置的页面计算中,允许小部件小于可见滚动大小,但将整个范围视为单个页面,并将其减go 基于页面的滚动像素计算,从而防止"页面"被放置在其侧面的小部件的半可见部分之前或之后.
另一个变化是,itemDimension
不是滚动范围除以元素数量,我需要这个值作为滚动方向上每个小部件的大小.
这就是我的结局:
当然,此实现有一些限制:
- 滚动方向上每个元素的大小必须是固定的,如果单个元素的大小不同,则整个滚动的行为会不规律
- 如果存在填充,那么大小必须包括填充,否则将产生与使用不同大小的小部件相同的效果
我没有把重点放在解决这个限制和拥有一个更完整的小部件上,因为在我需要这个小部件的情况下,这个限制是可以保证的.下面是上述示例的完整代码.
https://gist.github.com/rolurq/5db4c0cb7db66cf8f5a59396faeec7fa