如何为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
更好。