PageView与页面缓存

217 阅读2分钟

1 PageView

PageView 是一个非常重要的组件,因为在移动端开发中很常用

比如大多数 App 都包含 Tab 换页效果、图片轮动以及抖音上下滑页切换视频功能等等

这些都可以通过 PageView 轻松实现

PageView({
  Key? key,
  this.scrollDirection = Axis.horizontal, // 滑动方向
  this.reverse = false,
  PageController? controller,
  this.physics,
  List<Widget> children = const <Widget>[],
  this.onPageChanged,
  
  //每次滑动是否强制切换整个页面,如果为false,则会根据实际的滑动距离显示页面
  this.pageSnapping = true,
  //主要是配合辅助功能用的,后面解释
  this.allowImplicitScrolling = false,
  //后面解释
  this.padEnds = true,
})

创建一个 PageView

@override
Widget build(BuildContext context) {
  var children = <Widget>[];
  // 生成 6 个 Tab 页
  for (int i = 0; i < 6; ++i) {
    children.add( Page( text: '$i'));
  }

  return PageView(
    // scrollDirection: Axis.vertical, // 滑动方向为垂直方向
    children: children,
  );
}

2 页面缓存

每当页面切换时都会触发新 Page 页的 build,比如我们从第一页滑到第二页,然后再滑回第一页时,控制台打印如下:

flutter: build 0
flutter: build 1
flutter: build 0

1、PageView 默认并没有缓存功能,一旦页面滑出屏幕它就会被销毁,

2、和 ListView/GridView 不一样,在创建 ListView/GridView 时我们可以手动指定 ViewPort 之外多大范围内的组件需要预渲染和缓存(通过 cacheExtent 指定),只有当组件滑出屏幕后又滑出预渲染区域,组件才会被销毁,但是不幸的是 PageView 并没有 cacheExtent 参数!

3、在真实的业务场景中,对页面进行缓存是很常见的一个需求,比如一个新闻 App,下面有很多频道页,如果不支持页面缓存,则一旦滑到新的频道旧的频道页就会销毁,滑回去时又得重新请求数据和构建页面。

知识点: 虽然 PageView 没有透传 cacheExtent,但是却在allowImplicitScrolling 为 true 时设置了预渲染区域,注意,此时的缓存类型为 CacheExtentStyle.viewport,则 cacheExtent 则表示缓存的长度是几个 Viewport 的宽度,cacheExtent 为 1.0,则代表前后各缓存一个页面宽度,即前后各一页

既然如此,那我们将 PageView 的 allowImplicitScrolling 置为 true 则不就可以缓存前后两页了

修改代码,然后运行示例,发现在第一页时,控制台打印信息如下:

flutter: build 0
flutter: build 1 // 预渲染第二页

滑到第二页时:

flutter: build 0
flutter: build 1
flutter: build 2 // 预渲染第三页

当再滑回第一页时,控制台信息不变,这也就意味着第一页缓存成功,它没有被重新构建。

但是如果从第二页滑到第三页,然后再滑回第一页时,控制台又会输出 ”build 0“,这也符合预期,因为我们之前分析的就是设置  allowImplicitScrolling 置为 true 时就只会缓存前后各一页,所以滑到第三页时,第一页就会销毁。