备案 控制台
开发者社区 云原生 文章 正文

Flutter 108: 图解 PageView 滑动页面预览小尝试

简介: 0 基础学习 Flutter,第一百零八步:学习一下 PageView 的基本应用!

      PageView 滑动页面预览应用在很多场景中,小菜之前只用过最基本的用法,今天小菜尝试系统性的学习一下 PageView 的基本应用;

      PageView 一般用户少量需要滑动页面切换的场景,但整体使用很灵活,常用作切换 Tab 页或活动 Banner 等;

源码分析

PageView({
    Key key,
    this.scrollDirection = Axis.horizontal,     // 页面滑动方向(水平/竖直)
    this.reverse = false,           // 是否反向滑动
    PageController controller,      // 页面控制器
    this.physics,                   // 滑动到首页和末页动画效果
    this.pageSnapping = true,       // 是否整页滑动
    this.onPageChanged,             // 页面监听滑动回调
    List<Widget> children = const <Widget>[],   // Page 页面展示子 Widget
    this.dragStartBehavior = DragStartBehavior.start,
})

PageView.builder({
    Key key,
    this.scrollDirection = Axis.horizontal,
    ...
    this.dragStartBehavior = DragStartBehavior.start,
})

PageView.custom({
    Key key,
    this.scrollDirection = Axis.horizontal,
    ...
    this.dragStartBehavior = DragStartBehavior.start,
})

      分析源码可得,PageView 是一个有状态的 StatefulWidget 小部件,主要通过 PageControlleronPageChanged 控制滑动与数据监听,并且提供了两种命名构造方法,小菜逐个学习属性特性;

案例尝试

默认构造函数

1. PageView()

      小菜首先使用默认构造函数生成一个基本的 PageView

return Container( height: 240,
    child: PageView(children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

2. scrollDirection

      scrollDirection 主要用于 PageView 滑动方向,分别为 Axis.horizontal 水平方向和 Axis.vertical 竖直方向;

return Container( height: 240,
    child: PageView(scrollDirection: Axis.horizontal, children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

3. pageSnapping

      pageSnapping 用于是否禁止页面捕捉,小菜理解为 Page 页面是否为整页滑动切换;当 pageSnapping=false 时,Page 页可以逐步滑动,滑动到中途一半的时候也可以停止;

return Container( height: 240,
    child: PageView(pageSnapping: false, children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

4. reverse

      reverse 用于是否默认反向滑动,与 ListView 类似,PageView 默认初始从左往右或从上到下;reverse=true 即默认方向想法,为从右往左或从下往上;

return Container( height: 240,
    child: PageView(reverse: true, children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

5. onPageChanged

      onPageChanged 是页面监听的回调,当页面切换时,会返回当前 Position,可以根据当前具体位置进行业务处理;

return Container( height: 240,
    child: PageView(onPageChanged: (position) => print('Current index = ${position + 1}'), 
    children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

6. physics

      physics 主要体现在首页和尾页结束时动画动画效果,为 ScrollPhysics 类型,可以自定义也可以根据 Flutter 提供的动画来处理;类似的有 ClampingScrollPhysicsBouncingScrollPhysics 等;

return Container( height: 240,
    child: PageView(physics: BouncingScrollPhysics(), children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

7. controller

      controllerPageView 的控制器,可以设置页面跳转或者初始化位置,以及滑动动画效果等;

class PageController extends ScrollController {
  PageController({
    this.initialPage = 0,
    this.keepPage = true,
    this.viewportFraction = 1.0,
  })
}

      简单了解 PageController 源码,主要涉及 initialPage 初始化展示的 Page 页数组下标;keepPage 是否保存数据状态;viewportFraction 为每个 Page 页占据整个 PageView 比例;

      PageController 还提供了几个重要的方法,包括 animateToPagejumpToPage 等进行具体 Page 页切换,与其他的 Widget 联动;

PageController _controller;

@override
void initState() {
  super.initState();
  _controller = PageController(initialPage: 1, viewportFraction: 0.75);
}

return Container( height: 240,
    controller: _controller, children: <Widget>[
      _itemCard(0), _itemCard(1), _itemCard(2), _itemCard(3)
    ]));

PageView.builder

      PageView 提供了便利的 .builder() 构造方法,适用于大量动态或类似的 Widget,类似于 ListView.builder() 方式,注意:其中 itemCount 不可为空,当不设置 itemCount 时,PageView 会默认为无限循环,数组会一直增加;

      其中当我们需要与外界其他 Widget 联动时,可通过 PageController 进行 Page 页切换或直接跳转等;

_bodyWid() {
  return Column(children: <Widget>[
    Container( height: 60, color: Colors.green.withOpacity(0.8),
        child: Row(children: <Widget>[
          Expanded( child: GestureDetector(
                  child: Row( mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text('目录', style: TextStyle( fontSize: 16.0, color: Colors.white)),
                        Icon(Icons.arrow_downward, color: Colors.white)
                      ]),
                  onTap: () {
                    print('---GestureDetector--目录---');
                    setState(() {});
                    _currentIndex = 0;
                    _controller.animateToPage(0, duration: Duration(milliseconds: 400), curve: Curves.easeInOut);
                  })),
          Container(width: 0.5, color: Colors.white),
          Expanded( child: GestureDetector(
                  child: Center( child: Text('书签', style: TextStyle( fontSize: 16.0, color: Colors.white))),
                  onTap: () {
                    print('---GestureDetector--书签---');
                    setState(() {});
                    _currentIndex = 1;
                    _controller.animateToPage(1, duration: Duration(milliseconds: 400), curve: Curves.easeInOut);
                  }))
        ])),
    _leftMenuPage()
  ]);
}

_leftMenuPage() {
  return Expanded(
      child: PageView.builder(
          itemBuilder: (context, position) => _leftItemPage(context, position),
          itemCount: 2, controller: _controller,
          onPageChanged: (position) {
            print('PageView.onPageChanged---$position');
            setState(() { if (_currentIndex != position) { _currentIndex = position; } });
          }));
}

PageView.custom

      PageView 还提供了 .custom() 构造方法;可以通过 SliverChildBuilderDelegate 代理添加 Page 页面懒加载还可以进行 Page 页重新排列,这也是 .builder() 构造方法所不支持的;

return Container( height: 240,
    child: PageView.custom(
        controller: _controller,
        childrenDelegate: SliverChildBuilderDelegate((BuildContext context, int index) => _itemTransCard(index), childCount: 4)));

_itemTransCard(index) {
  Matrix4 _matrix = Matrix4.identity();
  print('---_itemTransCard-${_currentPageValue.floor()}-');
  if (index == _currentPageValue.floor()) {
    // The Current Page Item
    var currScale = 1 - (_currentPageValue - index) * (1 - _scaleFactor);
    var currTrans = 240.0 * (1 - currScale) / 2;
    _matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)..setTranslationRaw(0.0, currTrans, 0.0);
    return Transform(transform: _matrix, child: _itemCard(index));
  } else if (index == _currentPageValue.floor() + 1) {
    // The Right Page Item
    var currScale = _scaleFactor + (_currentPageValue - index + 1) * (1 - _scaleFactor);
    var currTrans = 240.0 * (1 - currScale) / 2;
    _matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)..setTranslationRaw(0.0, currTrans, 0.0);
    return Transform(transform: _matrix, child: _itemCard(index));
  } else if (index == _currentPageValue.floor() - 1) {
    // The Left Page Item
    var currScale = 1 - (_currentPageValue - index) * (1 - _scaleFactor);
    var currTrans = 240.0 * (1 - currScale) / 2;
    _matrix = Matrix4.diagonal3Values(1.0, currScale, 1.0)..setTranslationRaw(0.0, currTrans, 0.0);
    return Transform(transform: _matrix, child: _itemCard(index));
  } else {
    // Else
    _matrix = Matrix4.diagonal3Values(1.0, _scaleFactor, 1.0)..setTranslationRaw(0.0, 240.0 * (1 - _scaleFactor) / 2, 0.0);
    return Transform(transform: _matrix, child: _itemCard(index));
  }
}

      小菜在测试过程中,当初始化展示的 Page 页非首页时,展示效果有问题,所对应的并没有展示到该有的缩放尺寸,而依旧是默认首页是正常缩放尺寸;小菜发现,初始化时,_currentPageValue 还未从 PageController.addListener() 中监听赋值,默认为 0,因此导致展示错误,小菜对 _currentPageValue 设置初始化位置赋值即可;

var _initialIndex = 1;
var _currentPageValue = 0.0;

@override
void initState() {
  super.initState();
//    _controller = PageController();
  _controller =
      PageController(initialPage: _initialIndex, viewportFraction: 0.75);
  _currentPageValue = _initialIndex * 1.0;
  _controller.addListener(() {
    print('--CurrentPage--${_controller.page}');
    _currentPageValue = _controller.page;
    setState(() {});
  });
}


       PageView 案例源码


      小菜对 PageView 的底层还不够深入,可以自定义很多酷炫效果,建议多多尝试;如有错误,请多多指导!

来源: 阿策小和尚

阿策~
目录
相关文章
jcLee95
|
7月前
|
前端开发 机器人 数据安全/隐私保护
Flutter笔记:手写并发布一个人机滑动验证码插件
写 Flutter 项目时,遇到需要滑块验证码功能。滑块验证码属于人机验证码的一种,看起来像是在一个图片中“挖去”了一块,然后通过用户手动操作滑块,让被“挖去”的部分移回来。由于我不想使用各种第三方模块,因此决定自己实现一个初版以后慢慢添砖加瓦。本文是对第一个版本的一点记录。
jcLee95
191 1
Flutter笔记:手写并发布一个人机滑动验证码插件
过分的规定
|
8天前
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套
Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套 在 Flutter 中,ListView 和 PageView 是两个常用的控件,它们可以用于滑动展示大量内容的场景,且支持各种嵌套方式,本文将介绍其中的一些花式嵌套方式。
过分的规定
118 0
编程的平行世界
|
缓存
Flutter ListView懒加载(滑动不加载,停止滑动加载)
前言:为了更好的减小网络的带宽,使得列表更加流畅,我们需要了解懒加载,也称延迟加载。关于上一章的登录界面,各位属实难为我了,我也在求ui小姐姐,各位点点赞给我点动力吧~
编程的平行世界
973 0
jcLee95
|
8天前
Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例
Flutter笔记:使用Flutter构建响应式PC客户端/Web页面-案例
jcLee95
67 0
江上清风山间明月
|
11月前
|
UED 索引
Flutter仿写微信导航栏快速实现页面导航
Flutter仿写微信导航栏快速实现页面导航
江上清风山间明月
188 0
江上清风山间明月
|
11月前
Flutter页面返回数据传递
Flutter页面返回数据传递
江上清风山间明月
92 0
yechaoa
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
Flutter 底部导航栏BottomNavigationBar,并关联PageView实现滑动切换
yechaoa
312 0
编程的平行世界
|
iOS开发 容器
重识Flutter 在不同的滑动列表场景,请选择合适的Slivers - part2
在Flutter中,碰到复杂的、不同的滑动业务场景,若是选择了一个合适的Slivers组件,那么我认为问题会变得简单!
编程的平行世界
37974 3
重识Flutter 在不同的滑动列表场景,请选择合适的Slivers - part2
编程的平行世界
|
容器
重识Flutter 用于解决复杂滑动视窗问题的Slivers - part1
在日常的开发工作中,仅仅使用ListView、ListView.builder等这样的滑动组件就能满足大部分的业务需求,但在碰到较为复杂的滑动页面时,我认为Slivers可以帮你更简单的实现。
编程的平行世界
52878 4
重识Flutter  用于解决复杂滑动视窗问题的Slivers - part1
程序猿在广东
如何用一行代码实现Flutter页面变灰效果?
如何用一行代码实现Flutter页面变灰效果?
程序猿在广东
132 0
如何用一行代码实现Flutter页面变灰效果?

热门文章

最新文章

  • 1
    Flutter 插件站新升级: 加入优秀 GitHub 开源项目
  • 2
    对象存储oss使用问题之flutter使用http库进行post请求文件上传返回400如何解决
  • 3
    Flutter的网络请求:使用Dart进行HTTP请求的技术详解
  • 4
    【专栏】对比分析两种流行的跨平台开发框架——Flutter和React Native,探讨它们的优势、劣势以及适用场景
  • 5
    Flutter应用的国际化支持:实现多语言环境的优雅策略
  • 6
    Flutter的动画:实现方式与动画库的技术探索
  • 7
    Flutter的Widget基础:概念、分类与深入探索
  • 8
    Flutter 中优雅切换应用主题的组件
  • 9
    移动应用的未来之路:Flutter框架与跨平台开发
  • 10
    构建未来:使用Flutter框架开发跨平台移动应用
  • 1
    构建响应式Web界面:Flutter的跨界前端技术
    72
  • 2
    Flutter 动态修改应用图标功能指南
    105
  • 3
    盘点主流 Flutter 状态管理库2024
    106
  • 4
    Flutter - Dart 基础(数据类型)
    78
  • 5
    Flutter开发LongPressDraggable、Draggable 的onDragEnd没有被调用
    74
  • 6
    Flutter - Dart 基础(关于 var、null、late、const、final 等等)
    67
  • 7
    解决windows安装Flutter时出现Unknown operating system. Cannot install Dart SDK.问题
    55
  • 8
    跨平台开发框架Flutter在移动应用开发中的应用与前景
    88
  • 9
    Flutter插件开发指南02: 事件订阅 EventChannel
    83
  • 10
    Flutter插件开发指南01: 通道Channel的编写与实现
    69
  • 相关电子书

    更多
  • 基于flutter的产品应用实践
  • 《Flutter in action》
  • 闲鱼《Flutter 技术解析与实战》
  • 下一篇
    2024年阿里云免费云服务器及学生云服务器申请教程参考

    深圳SEO优化公司丽水设计公司网站推荐连云港建网站价格池州网站改版哪家好包头网站搭建多少钱长春至尊标王哪家好晋中网站定制推荐嘉兴网页制作多少钱咸宁网站开发公司襄樊网站建设价格白银百搜标王潜江网站关键词优化多少钱银川关键词按天扣费价格曲靖网络推广推荐德州网站推广报价南联网站优化软件价格镇江网络营销价格衡阳关键词按天收费推荐吴忠网站搜索优化多少钱福州网站制作多少钱合肥外贸网站制作哪家好黔南百搜标王推荐怒江SEO按天计费价格衢州百度爱采购哪家好周口网站推广系统哪家好怀化网站关键词优化公司怒江网页制作价格韶关百度竞价报价临夏百度爱采购公司德阳关键词排名包年推广哪家好咸阳阿里店铺托管报价歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

    深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化