阅读 230

Flutter 中 PageView 的几种构建方式(源码解析)| Flutter Widgets

这是我参与更文挑战的第16天,活动详情查看: 更文挑战

前言

上一篇我们聊了怎样使用 PageView 搭建一个项目主页面骨架,这一篇我们聊聊他的几种构建方式和属性调配的内容。

PageView(页面布局)

第一种 - PageView 构造

这个其实上篇我们已经做了简单的使用了,这里我们看看源码和属性调配。

先看效果

02.gif

怎么使用?

上一篇我们已经做了简单的使用,这里只贴核心代码,全部代码可以看上篇聊的也可以看 GitHub 上的仓库源码(链接在下面)

// 子项集
children = [
  PageDetails(title: '首页'),
  PageDetails(title: '消息'),
  PageDetails(title: '我的'),
];
// 初始化控制器
_controller = PageController();

// 构造方式
PageView(
  // 设置控制器
  controller: _controller,
  // 设置子项集
  children: children,
)
复制代码
PageController(页面控制器)

这个控制器可以非常方面的操作 PageView 切换,下面我们来看看几个属性和方法

  • initialPage(初始在第几个页面)
  • keepPage(保持页面状态,上篇又聊到,这里也是必要的设置,默认是 true)
  • viewportFraction (页面占用窗口比例)

上面这几个属性,一般是在初始化的时候使用

// 初始化控制器
_controller = PageController(initialPage: 0);
复制代码
  • jumpToPage(直接跳转到指定页面,上篇我们有用到切换导航栏来切换页面)
_controller.jumpToPage(currentIndex);
复制代码
  • animateToPage(以动画的方式切换到指定的页面)
    • page 页面(指定页面)
    • duration(动画时间)
    • curve (动画曲线)
_controller.animateToPage(
  currentIndex,
  duration: Duration(milliseconds: 300),
  curve: Curves.easeIn,
);
复制代码

01.gif

  • nextPage(下一页)
  • previousPage(上一页)

这两个方法最后调用的都是 animateToPage ,所以也是要设置动画时间和动画曲线的,不过多介绍了。

PageView 属性调配

上面聊完了 PageController ,现在回来继续聊 PageView 的属性

  • scrollDirection(滚动方向)
    • Axis.horizontal(横向)
    • Axis.vertical(纵向)

上面看过了横向的,我们再看一下纵向的效果
02.gif

  • onPageChanged(页面滚动改变后监听)

上面的效果图页面滚动后,底部导航栏也是跟着滚动的,就是通过这个方法来配置的。

PageView(
  // 滚动方向
  scrollDirection: Axis.vertical,
  // 添加页面滑动改变后,去改变索引变量刷新页面来更新底部导航
  onPageChanged: (value) {
    currentIndex = value;
    setState(() {});
  },
)
复制代码
  • 其他的很多属性,但是不常用,就暂时不聊了

看看源码

image.png
当前我们使用 PageView 的构造方式,但是根据之前分析 ListViewGridView 经验,我们这里需要关注一下 643 行,因为最终子项集传递到 childrenDelegate 这里了,最终是根据他来构建的。

注意这里是 SliverChildListDelegate

第二种 - PageView.builder 构建

// 这里使用 builder 构建
PageView.builder(
  itemBuilder: (context, index) {
    // 返回子项 Widget
    return getItem(index);
  },
  // 设置子项个数
  itemCount: children.length,
)
复制代码

getItem

// 获取子项 Widget
Widget getItem(index) {
  // 项目中准备好的数据
  var item = listData[index];
  // 返回子项 Widget
  return Container(
    child: Stack(
      alignment: Alignment.center,
      children: [
        // 背景图
        Image.network(item.url),
        // 标题
        Positioned(
          top: 20,
          child: Text(item.title),
        ),
        // 描述
        Positioned(
          bottom: 40,
          child: Text(item.desc),
        ),
      ],
    ),
  );
}
复制代码

效果

03.gif

看看源码

image.png
其他的没啥好说的,都是一样的参数,但是注意 682 行,这里使用的是 SliverChildBuilderDelegate

第三种 - PageView.custom

看到这里是不是感觉回到了 ListView 和 GridView 的介绍,基本就是这几种构建方式,以及子项内容的构建也都是通用的 SliverChildListDelegateSliverChildBuilderDelegate

PageView.custom(
  // SliverChildListDelegate
  childrenDelegate: SliverChildListDelegate(children),
)
复制代码
PageView.custom(
  // SliverChildBuilderDelegate
  childrenDelegate: SliverChildBuilderDelegate(
    (BuildContext context, int index) {
      return getItem(index);
    },
    childCount: 3,
  ),
)
复制代码

源码

image.png
此处的源码 777 行就是直接使用 this.childrenDelegate 给赋值了

总结

到这里 PageView 的 3 种构建方式就聊完了,总结如下,如果觉得对比有帮助,记得点赞支持哦
image.png

源码仓库

基于 Flutter 🔥 最新版本

参考链接

关注专栏

  • 此文章已收录到下面👇 的专栏,可以直接关注
  • 更多文章继续阅读|系列文章持续更新

👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦

文章分类
Android
文章标签