我想用水平分页滚动呈现卡,并且每当看到一个卡时,便能够看到上一张和下一张卡的边框。颤抖的PageView小部件几乎可以产生我想要的结果,但是它并没有按照我想要的方式显示页面对齐,这是我的代码
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PageView Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'PageView Alignment'),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: PageView.builder(
itemCount: 5,
itemBuilder: (context, i) => Container(
color: Colors.blue,
margin: const EdgeInsets.only(right: 10),
child: Center(child: Text("Page $i")),
),
controller: PageController(viewportFraction: .7),
),
);
}
}
我希望将PageView对齐到屏幕的左侧,或者至少对齐第一页,即要删除Page 0
左侧的空白。我有缺少的PageView参数吗?还是存在一些其他组件,这些组件会产生我想要的结果?
答案 0 :(得分:3)
在根据自己的需要进行了更深入的分析并检查了PageView
小部件的源代码之后,我意识到我需要一个滚动小部件,该滚动小部件可以逐项工作,但与此同时,需要给每个项目分配的空间与普通滚动相同,因此我需要更改普通滚动器的ScrollPhysics
。在发现的this帖子中某种程度上描述了颤振中的滚动物理现象,并且与我的需求非常接近,不同之处在于,我需要在当前可见窗口小部件的咬合侧增加空间,而不仅仅是在右侧。
因此,我在帖子中使用了CustomScrollPhysics
并以此方式进行了修改(邮政编码中的更改部分被<--
和-->
注释所包围:
class CustomScrollPhysics extends ScrollPhysics {
final double itemDimension;
CustomScrollPhysics({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(
ScrollPosition 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
)剩余的一半空间,并根据滚动位置将其添加到页面计算中,从而使窗口小部件更小可见滚动的大小,但将整个范围视为一个页面,然后将其减去到基于页面的滚动像素计算中,以防止“页面”放置在小部件的一半可见部分的旁边或之前。
另一个变化是itemDimension
不是滚动范围除以元素数量,我需要将此值设为滚动方向上每个小部件的大小。
这就是我最终得到的:
当然,此实现有一些限制:
我不专注于解决此限制并拥有一个更完整的窗口小部件,因为在需要此窗口小部件的情况下可以确保此限制。这是上面示例的完整代码。
https://gist.github.com/rolurq/5db4c0cb7db66cf8f5a59396faeec7fa
答案 1 :(得分:0)
尝试根据这样的页面添加边距:
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: PageView.builder(
itemCount: 5,
itemBuilder: (context, i) => Container(
color: Colors.blue,
margin: i == 0
? const EdgeInsets.only(right: 10)
: const EdgeInsets.only(left: 10, right: 10),
child: Center(child: Text("Page $i")),
),
controller: PageController(),
),
);
}
}
结果: