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