Flutter PageView左右滑动切换视图

题记:不到最后时刻,千万别轻言放弃,无论结局成功与否,只要你拼博过,尽力过,一切问心无愧。

本文将通过 PageView 实现页面的整页横向切换。

1 PageView 的基本使用

///封装方法构建PageView组件 PageView buildBodyFunction() { ///可实现左右页面滑动切换 return PageView( //当页面选中后回调此方法 //参数[index]是当前滑动到的页面角标索引 从0开始 onPageChanged: (int index){ print("当前的页面是 $index"); ///滑动PageView时,对应切换选择高亮的标签 setState(() { currentSelectIndex = index; }); }, //值为flase时 显示第一个页面 然后从左向右开始滑动 //值为true时 显示最后一个页面 然后从右向左开始滑动 reverse: false, //滑动到页面底部无回弹效果 physics: BouncingScrollPhysics(), //横向滑动切换 scrollDirection: Axis.horizontal, //页面控制器 controller: pageController, //所有的子Widget children: pageList, ); }}

controller 与pageList

///当前显示标签页面的标识 int currentSelectIndex = 0; ///保存页面的List List pageList=[]; /// 初始化控制器 PageController pageController;

@override void initState() { super.initState(); ///创建控制器的实例 pageController = new PageController( ///用来配置PageView中默认显示的页面 从0开始 initialPage: 0, ///为true是保持加载的每个页面的状态 keepPage: true, );

///PageView设置滑动监听 pageController.addListener(() { //PageView滑动的距离 double offset = pageController.offset; print("pageView 滑动的距离 $offset"); });

///保存标签页面 pageList=[ LeftPage(), RightPage(), ];}

使用 controller 来实现PageView的整屏切换

pageController.animateTo( MediaQuery.of(context).size.width*currentSelectIndex, duration: Duration(milliseconds: 200), curve: Curves.linear);

使用PageView滑动到顶部

pageController.animateTo( 0, duration: Duration(milliseconds: 200), curve: Curves.linear);

2 案例实战 使用PageView实现引导页面

首先是通过 Stack 将圆点指示器 与 PageView 叠在一起显示,如下代码清单2-1所示:

///代码清单 2-1class LeftPageViewPage extends StatefulWidget { @override State createState() { return new LeftPageViewPageState(); }}

class LeftPageViewPageState extends State {

///控制器 final PageController _controller = new PageController(); ///可滑动的页面 使用到的图片 final List _pages = [ "http://b-ssl.duitang.com/uploads/item/201311/02/20131102150044_YGB5u.jpeg", "http://b-ssl.duitang.com/uploads/item/201311/02/20131102150044_YGB5u.jpeg", "http://b-ssl.duitang.com/uploads/item/201311/02/20131102150044_YGB5u.jpeg", ];

@override Widget build(BuildContext context) { ///层叠布局 return new Stack( children: [ //底层的PageView buildPageView(), //表层的圆点指示器 buildPositioned(), ], ); }}

通过 buildPageView 方法来构建一个 PageView ,如下代码清单 2-2 所示:

///代码清单 2-2 ///构建 PageView PageView buildPageView() { ///懒加载模式构建 return PageView.builder( ///设置滑动模式 physics: new AlwaysScrollableScrollPhysics(), ///添加控制器 controller: _controller, ///构建每一屏的视图 UI itemBuilder: (BuildContext context, int index) { return buildItemWidget(index); }, ///条目个数 itemCount: _pages.length, );}

PageView 通过 itemBuilder 属性来构建每一屏页面显示UI,在这里通过 buildItemWidget 方法封装构建如下代码清单2-3所示:

///代码清单 2-3 ///构建每一页的Item UI效果 Widget buildItemWidget(int index){ return new ConstrainedBox( constraints: const BoxConstraints.expand(), ///网络图片 child: Image.network( ///图片地址 _pages[index], ///加载中的占位 loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) { ///这里使用了一个进度圆圈 return new SizedBox( width: 24.0, height: 24.0, child: new CircularProgressIndicator( strokeWidth: 2.0, ), ); },), );}

通过方法 buildPositioned 来 结合Positioned 使用圆点组件在 Stack 中底部对齐,如下代码清单 2-4所示:

///代码清单 2-4 ///表层的圆点指示器 Positioned buildPositioned() { return new Positioned( ///底部对齐 bottom: 0.0, left: 0.0,right: 0.0, child: new Container( color: Colors.white, padding: const EdgeInsets.all(20.0), child: new Center( ///自定义的圆点切换指示器 child: buildDotsIndicator(), ), ), );}

buildDotsIndicator 方法用来构建建表层的圆点指示器,如下代码清单 2-5所示:

///代码清单 2-5 ///自定义的圆点切换指示器 DotsIndicator buildDotsIndicator() { return new DotsIndicator( ///与PageView联动的控制器 controller: _controller, ///小圆点的个数 itemCount: _pages.length, ///点击小圆点的回调 onPageSelected: (int pageIndex) { ///主动切换页面 _controller.animateToPage( pageIndex, duration: Duration(milliseconds: 300), curve: Curves.ease, ); });}

对于 DotsIndicator 是自定义的一个 AnimatedWidget,如下代码清单2-6所示:

///代码清单 2-6class DotsIndicator extends AnimatedWidget { DotsIndicator({ this.controller, this.itemCount, this.onPageSelected, this.color: Colors.red, }) : super(listenable: controller);

final PageController controller;

final int itemCount;

final ValueChanged onPageSelected;

final Color color;

static const double _kDotSize = 8.0;

static const double _kMaxZoom = 2.0;

static const double _kDotSpacing = 25.0;

Widget _buildDot(int index) { double selectedness = Curves.easeOut.transform( max( 0.0, 1.0 - ((controller.page ?? controller.initialPage) - index).abs(), ), ); double zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness; return new Container( width: _kDotSpacing, child: new Center( child: new Material( color: color, type: MaterialType.circle, child: new Container( width: _kDotSize * zoom, height: _kDotSize * zoom, child: new InkWell( onTap: () => onPageSelected(index), ), ), ), ), ); }

Widget build(BuildContext context) { return new Row( mainAxisAlignment: MainAxisAlignment.center, children: new List.generate(itemCount, _buildDot), ); }}

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200901A0PEJX00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券