Flutter开发Widgets 之 PageView使用示例

2022-10-09 17:15:33
目录
构造方法以及参数:基本用法无限滚动实现指示器切换动画总结:

构造方法以及参数:

PageView可用于Widget的整屏滑动切换,如当代常用的短视频APP中的上下滑动切换的功能,也可用于横向页面的切换,如APP第一次安装时的引导页面,也可用于开发轮播图功能.

  PageView({
    Key? key,
    this.scrollDirection = Axis.horizontal, // 设置滚动方向 垂直 / 水平 
    this.reverse = false,	// 反向滚动 
    PageController? controller,	// 滚动控制类 
    this.physics,	// 滚动逻辑 , 不滚动 / 滚动 / 滚动到边缘是否反弹 
    this.pageSnapping = true,	// 如果设置 false , 则无法进行页面手势捕捉 
    this.onPageChanged, 	// 页面切换时回调该函数 
    List<Widget> children = const <Widget>[],
    this.dragStartBehavior = DragStartBehavior.start,
    this.allowImplicitScrolling = false,
    this.restorationId,
    this.clipBehavior = Clip.hardEdge,
  }) : assert(allowImplicitScrolling != null),
       assert(clipBehavior != null),
       controller = controller ?? _defaultPageController,
       childrenDelegate = SliverChildListDelegate(children),
       super(key: key);

具体参数说明:

scrollDirection主要是滚动的方向即horizontal(水平)和vertical(垂直)两个,默认是horizontal的

reverse这个就是规定了children(子节点)的排序是否是倒序,默认false。这个参数在ListView也有,一般在做IM工具聊天内容用ListView展示时需要倒序展示的。

controller可以传入一个PageController的实例进去,可以更好的控制PageView的各种动作,可以设置:

    初始页面(initialPage)、是否保存PageView状态(keepPage)每一个PageView子节点的内容占改视图的比例(viewportFraction)直接调转到指定的PageView的子节点的方法(jumpToPage动画(平滑移动)到指定的PageView的子节点的方法(animateToPage)到下一个PageView的子节点的方法(nextPage)到上一个PageView的子节点的方法(previousPage)
    从以上可以看出基本是普通轮播图组件的API

    physics就是设置滑动效果:

      NeverScrollablePhysics表示设置的不可滚动BouncingScrollPhysics表示滚动到底了会有弹回的效果,就是iOS的默认交互ClampingScrollPhysics表示滚动到底了就给一个效果,就是Android的默认交互FixedExtentScrollPhysics就是ios经典选择时间组件UIDatePicker那种交互。

      pageSnapping就是设置是不是整页滚动,默认是true.

      dragStartBehavior这个属性是设置认定开始拖动行为的方式,可以选择的是down和start两个,默认是start. down是第一个手指按下认定拖动开始,start是手指拖动才算开始。

      allowImplicitScrolling这个属性一般提供给视障人士使用的,默认是fasle

      基本用法

      PageView控件可以实现一个“图片轮播”的效果,PageView不仅可以水平滑动也可以垂直滑动,简单用法如下:

      PageView(
            children: [
              Container(color: Colors.red,),
              Container(color: Colors.black,),
              Container(color: Colors.yellow,),
            ],
          );
      

      PageView滚动方向默认是水平,可以设置其为垂直方向:

      PageView(
          scrollDirection: Axis.vertical,
          ...
      )
      

      PageView配合PageController可以实现非常酷炫的效果,控制每一个Page不占满,

      Container(
            height:200 ,
            child: PageView(
              scrollDirection: Axis.horizontal,
              controller: PageController(viewportFraction: 0.9),
              children: [
                Container(color: Colors.red,),
                Container(color: Colors.black,),
                Container(color: Colors.yellow,),
              ],
            ),
          );
      

      PageController中属性initialPage表示当前加载第几页,默认第一页。

      onPageChanged属性是页面发生变化时的回调,用法如下:

      无限滚动

      PageView滚动到最后时希望滚动到第一个页面,这样看起来PageView是无限滚动的:

      List<Widget> pageList = [PageView1(), PageView2(), PageView3()];
      PageView.builder(
          itemCount: 10000,
          itemBuilder: (context, index) {
              return pageList[index % (pageList.length)];
          },
      )
      

      实现指示器

      指示器显示总数和当前位置,通过onPageChanged确定当前页数并更新指示器。

       int _currentPageIndex = 0;
        List<Widget> pageList = [ Container(color: Colors.red,),
          Container(color: Colors.black,),
          Container(color: Colors.yellow,),];
       _buildPageView(){
          return Center(
            child: Container(
              height: 230,
              child: Stack(
                children: [
                  PageView.builder(itemBuilder: (context,index){
                    var val = pageList[index%(pageList.length)];
                    print(val);
                    return _buildPageViewItem('${val}');
                  }),
                  Positioned(
                      bottom: 20,
                      left: 0,
                      right: 0,
                      child: Container(
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: List.generate(pageList.length, (i){
                            return Container(
                              margin: EdgeInsets.symmetric(horizontal: 5),
                              width: 10,
                              height: 10,
                              decoration: BoxDecoration(
                                shape: BoxShape.circle,
                                color: _currentPageIndex==i?Colors.blue:Colors.grey
                              ),
                            );
                          }).toList(),
                        ),
                      )
                  )
                ],
              ),
            ),
          );
        }
        _buildPageViewItem(String txt,{Color color=Colors.red}){
          return Container(
            color: color,
            alignment: Alignment.center,
            child: Text(txt,style: TextStyle(color: Colors.white,fontSize: 25),),
          );
        }
      

      切换动画

      如此常见的切换效果显然不能体验我们独特的个性,我们需要更炫酷的方式,看下面的效果:

      在滑出的时候当前页面逐渐缩小并居中,通过给PageController添加监听获取当前滑动的进度:

      _pageController.addListener(() {
            setState(() {
              _currPageValue = _pageController.page;
            });
          });
      

      全部代码:

      /**
       * @Author wywinstonwy
       * @Date 2022/10/05 9:50 上午
       * @Description:
       */
      import 'package:demo202112/utils/common_appbar.dart';
      import 'package:flutter/material.dart';
      class WyPageView1 extends StatefulWidget {
        const WyPageView1({Key? key}) : super(key: key);
        @override
        _WyPageViewState createState() => _WyPageViewState();
      }
      class _WyPageViewState extends State<WyPageView1> {
        int _currentPageIndex = 0;
        var imgList = [
          'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2877516247,37083492&fm=26&gp=0.jpg',
          'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1582796218195&di=04ce93c4ac826e19067e71f916cec5d8&imgtype=0&src=http%3A%2F%2Fhbimg.b0.upaiyun.com%2F344fda8b47808261c946c81645bff489c008326f15140-koiNr3_fw658'
        ];
        late PageController _pageController;
        var _currPageValue=0;
        //缩放系数
        double _scaleFactor = .8;
        //view page height
        double _height = 230.0;
        @override
        void initState() {
          // TODO: implement initState
          super.initState();
          _pageController=PageController(viewportFraction: 0.9);
          _pageController.addListener(() {
            setState(() {
              _currPageValue = _pageController.page;
            });
          });
        }
        @override
        void dispose() {
          // TODO: implement dispose
          super.dispose();
          _pageController.dispose();
        }
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: getAppBar('PageView'),
            body: Container(
                height: _height,
                child: PageView.builder(
                  itemBuilder: (context, index) => _buildPageItem(index),
                  itemCount: 10,
                  controller: _pageController,
                )),
          );
        }
        _buildPageItem(int index) {
          Matrix4 matrix4 = Matrix4.identity();
          if (index == _currPageValue.floor()) {
            //当前的item
            double currScale = (1 - (_currPageValue - index) * (1 - _scaleFactor)).toDouble();
            var currTrans = _height * (1 - currScale) / 2;
            matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0)
              ..setTranslationRaw(0.0, currTrans, 0.0);
          } else if (index == _currPageValue.floor() + 1) {
            //右边的item
            var currScale =
                _scaleFactor + (_currPageValue - index + 1) * (1 - _scaleFactor);
            var currTrans = _height * (1 - currScale) / 2;
            matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0)
              ..setTranslationRaw(0.0, currTrans, 0.0);
          } else if (index == _currPageValue.floor() - 1) {
            //左边
            var currScale = (1 - (_currPageValue - index) * (1 - _scaleFactor)).toDouble();
            var currTrans = _height * (1 - currScale) / 2;
            matrix4 = Matrix4.diagonal3Values(1.0, currScale, 1.0)
              ..setTranslationRaw(0.0, currTrans, 0.0);
          } else {
            //其他,不在屏幕显示的item
            matrix4 = Matrix4.diagonal3Values(1.0, _scaleFactor, 1.0)
              ..setTranslationRaw(0.0, _height * (1 - _scaleFactor) / 2, 0.0);
          }
          return Transform(
            transform: matrix4,
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 10),
              child: Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(12),
                  image: DecorationImage(
                      image: NetworkImage(imgList[index % 2]), fit: BoxFit.fill),
                ),
              ),
            ),
          );
        }
      }
      

      gitdemo地址:gitee.com/wywinstonwy…

      总结:

      相比熟悉Android和IOS开发的同学都会比较熟悉ViewPager,可以在界面上滑动多个界面View的切换。在Flutter中同样有这样的组建那就是PageView,相比于ViewPager它有着更加强大的功能,毕竟Flutter中Widget是一等公民,在实际开发中也是比较实用的组件,可以提升开发效率。

      以上就是Flutter开发Widgets>