如何为ListView中的每一项实现 PageView 滑动的效果?
因为 PageView 会独占整个显示区域的剩余部分,必须包上如 SizedBox 这样的限定尺寸的 Widget 才可以把它放到 ListView 中。但是 SizedBox 需要提前设置 height 和 width,但并没有很好的办法提前获取子元素的尺寸,而固定一个尺寸很多时候并不能满足需求。
经过研究,解决方法其实非常简单,即使用 SingleChildScrollView + PageScrollPhysics + PageController,就可以完美的实现 PageView 的效果,包括:
1. 滑动的动画,
2. 吸附到边界(snapping),
3. 指定初始页面索引。
4. 如果需要获取页面切换通知,使用 NotificationListener 包裹SingleChildScrollView即可。
NotificationListener<ScrollNotification>( onNotification: (ScrollNotification notification) { if (notification.depth == 0 && notification is ScrollUpdateNotification) { final PageMetrics metrics = notification.metrics as PageMetrics; final int currentPage = metrics.page!.round(); if (currentPage != _lastReportedPage) { _lastReportedPage = currentPage;
if (widget.onPageChanged != null) { widget.onPageChanged!(currentPage); } } } return false; },
|
SingleChildScrollView 的子元素:
... ... screenSize ??= MediaQuery.of(context).size; ... ... SingleChildScrollView( scrollDirection: Axis.horizontal, physics: const PageScrollPhysics(), controller: this.controller, child: SizedBox( width: screenSize!.width * 2, child: Row( mainAxisSize: MainAxisSize.min, children: [ Flexible(child: xxx), Flexible(child: xxx), ], ), ), ),
|
上面的 screenSize 的获取,使用 LayoutBuilder 更好。