构造方法以及参数:

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://hbimg.b0.upaiyun.com/344fda8b47808261c946c81645bff489c008326f15140-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 之 PageView使用示例的详细内容,更多关于Flutter开发Widgets PageView的资料请关注Devmax其它相关文章!

Flutter开发Widgets 之 PageView使用示例的更多相关文章

  1. Flutter中文教程-Cookbook

    Flutter中文网的Cookbook中包含了在编写Flutter应用程序时常见问题及示例。设计基础使用主题共享颜色和字体样式Images显示来自网上的图片用占位符淡入图片使用缓存图Lists创建一个基本list创建一个水平list使用长列表创建不同类型子项的List创建一个gridList处理手势处理点击添加Material触摸水波效果实现滑动关闭导航导航到新页面并返回给新页面传值从新页面返回数据给上一个页面网络从网上获取数据进行认证请求使用WebSockets

  2. android-studio – 未配置Dart SDK

    Initializinggradle…

  3. 安卓 – 从一个扑动的应用程序拨打电话

    或者有更好的选择从我的应用程序拨打电话?

  4. android – 如何在Flutter中添加Webview?

    我知道可以将WebView添加为整页,但找不到任何示例代码.我假设你可以使用PageView作为它的基础,但不知道如何调用本机androidWebView并将其添加到PageView.谁能指出我正确的方向?

  5. android – 如何将消息从Flutter传递给Native?

    如果需要与特定的API/硬件组件进行交互,您如何将Flutter的信息传递回Android/Native代码?是否有任何事件频道可以通过其他方式发送信息或类似于回调?

  6. android – 如何在Flutter App中处理onPause / onResume?

    我是否过于复杂的事情?即使我的用例似乎不需要它,我仍然想知道:如何自己处理onPause/onResume事件?

  7. android – 如何使用Flutter构建Augment Reality应用程序?

    我对Android开发有一些基础知识.最近听说过Flutter并且非常有兴趣研究它.我想知道是否有可能使用颤振构建增强现实应用程序以及要实现此目的的方法?请帮忙.解决方法截至目前,颤振不支持3D.Flutter现在专注于2D,团队长期计划为颤振提供优化的3Dapi.你读了常见问题here.

  8. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  9. Flutter StreamBuilder实现局部刷新实例详解

    这篇文章主要为大家介绍了Flutter StreamBuilder实现局部刷新实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. Flutter 首页必用组件NestedScrollView的示例详解

    今天介绍的组件是NestedScrollView,大部分的App首页都会用到这个组件。对Flutter 首页必用组件NestedScrollView的相关知识感兴趣的一起看看吧

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部