可滚动Widget

ViewPort视口

在Flutter中,术语ViewPort(视口),如无特别说明,则是指一个Widget的实际显示区域。例如,一个ListView的显示区域高度是800像素,虽然其列表项总高度可能远远超过800像素,但是其ViewPort仍然是800像素。

主轴和纵轴

在可滚动widget的坐标描述中,通常将滚动方向称为主轴,非滚动方向称为纵轴。由于可滚动widget的默认方向一般都是沿垂直方向,所以默认情况下主轴就是指垂直方向,水平方向同理。

Scrollable

当内容超过显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误。为此,Flutter提供了多种可滚动widget(Scrollable Widget)用于显示列表和长布局。可滚动Widget都直接或间接包含一个Scrollable widget:

Scrollable({...this.axisDirection = AxisDirection.down,this.controller,this.physics,@required this.viewportBuilder, //后面介绍
})
  • axisDirection:滚动方向。
  • physics:此属性接受一个ScrollPhysics对象,它决定可滚动Widget如何响应用户操作,比如用户滑动完抬起手指后,继续执行动画;或者滑动到边界时,如何显示。
  • controller:此属性接受一个ScrollController对象。ScrollController的主要作用是控制滚动位置和监听滚动事件。

Scrollbar

Scrollbar是一个Material风格的滚动指示器(滚动条),如果要给可滚动widget添加滚动条,只需将Scrollbar作为可滚动widget的父widget即可,如:

Scrollbar(child: SingleChildScrollView(...),
);

SingleChildScrollView

SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子Widget。定义如下:

SingleChildScrollView({this.scrollDirection = Axis.vertical, //滚动方向,默认是垂直方向this.reverse = false, this.padding, bool primary, this.physics, this.controller,this.child,
})

除了通用属性,我们重点看一下reverse和primary两个属性:

  • reverse:该属性API文档解释是:是否按照阅读方向相反的方向滑动,
  • primary:指是否使用widget树中默认的PrimaryScrollController;当滑动方向为垂直方向(scrollDirection值为Axis.vertical)并且controller没有指定时,primary默认为true.

ListView

ListView是最常用的可滚动widget,它可以沿一个方向线性排布所有子widget。我们看看ListView的默认构造函数定义:

ListView({...  //可滚动widget公共参数Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,EdgeInsetsGeometry padding,//ListView各个构造函数的共同参数  double itemExtent,bool shrinkWrap = false,bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,double cacheExtent,//子widget列表List<Widget> children = const <Widget>[],
})
  • itemExtent:该参数如果不为null,则会强制children的"长度"为itemExtent的值;这里的"长度"是指滚动方向上子widget的长度,即如果滚动方向是垂直方向,则itemExtent代表子widget的高度,如果滚动方向为水平方向,则itemExtent代表子widget的长度。

  • shrinkWrap:该属性表示是否根据子widget的总长度来设置ListView的长度,默认值为false 。默认情况下,ListView的会在滚动方向尽可能多的占用空间。当ListView在一个无边界(滚动方向上)的容器中时,shrinkWrap必须为true。

  • addAutomaticKeepAlives:该属性表示是否将列表项(子widget)包裹在AutomaticKeepAlive widget中;典型地,在一个懒加载列表中,如果将列表项包裹在AutomaticKeepAlive中,在该列表项滑出视口时该列表项不会被GC,它会使用KeepAliveNotification来保存其状态。如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。

  • addRepaintBoundaries:该属性表示是否将列表项(子widget)包裹在RepaintBoundary中。当可滚动widget滚动时,将列表项包裹在RepaintBoundary中可以避免列表项重绘,但是当列表项重绘的开销非常小(如一个颜色块,或者一个较短的文本)时,不添加RepaintBoundary反而会更高效。和addAutomaticKeepAlive一样,如果列表项自己维护其KeepAlive状态,那么此参数必须置为false。

ListView.builder

ListView.builder适合列表项比较多(或者无限)的情况,因为只有当子Widget真正显示的时候才会被创建。下面看一下ListView.builder的核心参数列表:

ListView.builder({// ListView公共参数已省略  ...@required IndexedWidgetBuilder itemBuilder,int itemCount,...
})
  • itemBuilder:它是列表项的构建器,类型为IndexedWidgetBuilder,返回值为一个widget。当列表滚动到具体的index位置时,会调用该构建器构建列表项。
  • itemCount:列表项的数量,如果为null,则为无限列表。

ListView.separated

ListView.separated可以生成列表项之间的分割器,它除了比ListView.builder多了一个separatorBuilder参数,该参数是一个分割器生成器。

class ListView3 extends StatelessWidget {@overrideWidget build(BuildContext context) {//下划线widget预定义以供复用。  Widget divider1=Divider(color: Colors.blue,);Widget divider2=Divider(color: Colors.green);return ListView.separated(itemCount: 100,//列表项构造器itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));},//分割器构造器separatorBuilder: (BuildContext context, int index) {return index%2==0?divider1:divider2;},);}
}

GridView

GridView可以构建一个二维网格列表,其默认构造函数定义如下:

GridView({Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,bool shrinkWrap = false,EdgeInsetsGeometry padding,@required SliverGridDelegate gridDelegate, //控制子widget layout的委托bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,double cacheExtent,List<Widget> children = const <Widget>[],
})
  • gridDelegate参数,类型是SliverGridDelegate,它的作用是控制GridView子widget如何排列(layout)。

SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法,Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent:

SliverGridDelegateWithFixedCrossAxisCount

该子类实现了一个横轴为固定数量子元素的layout算法,其构造函数为:

SliverGridDelegateWithFixedCrossAxisCount({@required double crossAxisCount,double mainAxisSpacing = 0.0,double crossAxisSpacing = 0.0,double childAspectRatio = 1.0,
})
  • crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即ViewPort横轴长度/crossAxisCount。
  • mainAxisSpacing:主轴方向的间距。
  • crossAxisSpacing:横轴方向子元素的间距。
  • childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在主轴的长度。

可以发现,子元素的大小是通过crossAxisCount和childAspectRatio两个参数共同决定的。

GridView.count

GridView.count构造函数内部使用了SliverGridDelegateWithFixedCrossAxisCount,我们通过它可以快速的创建横轴固定数量子元素的GridView:

GridView.count(crossAxisCount: 3,childAspectRatio: 1.0,children: <Widget>[Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
);

SliverGridDelegateWithMaxCrossAxisExtent

该子类实现了一个横轴子元素为固定最大长度的layout算法,其构造函数为:

SliverGridDelegateWithMaxCrossAxisExtent({double maxCrossAxisExtent,double mainAxisSpacing = 0.0,double crossAxisSpacing = 0.0,double childAspectRatio = 1.0,
})
  • maxCrossAxisExtent为子元素在横轴上的最大长度,之所以是“最大”长度,是因为横轴方向每个子元素的长度仍然是等分的,
  • childAspectRatio所指的子元素横轴和主轴的长度比为最终的长度比。其它参数和SliverGridDelegateWithFixedCrossAxisCount相同。

GridView.extent

GridView.extent构造函数内部使用了SliverGridDelegateWithMaxCrossAxisExtent,我们通过它可以快速的创建纵轴子元素为固定最大长度的的GridView:

GridView.extent(maxCrossAxisExtent: 120.0,childAspectRatio: 2.0,children: <Widget>[Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],);

GridView.builder

上面我们介绍的GridView都需要一个Widget数组作为其子元素,这些方式都会提前将所有子widget都构建好,所以只适用于子Widget数量比较少时,当子widget比较多时,我们可以通过GridView.builder来动态创建子Widget。GridView.builder 必须指定的参数有两个:

GridView.builder(...@required SliverGridDelegate gridDelegate, @required IndexedWidgetBuilder itemBuilder,
)

其中itemBuilder为子widget构建器。

CustomScrollView

CustomScrollView是可以使用sliver来自定义滚动模型(效果)的widget。它可以包含多种滚动模型,举个例子,假设有一个页面,顶部需要一个GridView,底部需要一个ListView,而要求整个页面的滑动效果是统一的,即它们看起来是一个整体,如果使用GridView+ListView来实现的话,就不能保证一致的滑动效果,因为它们的滚动效果是分离的,所以这时就需要一个"胶水",把这些彼此独立的可滚动widget(Sliver)"粘"起来,而CustomScrollView的功能就相当于“胶水”。

Sliver

Sliver有细片、小片之意,在Flutter中,Sliver通常指具有特定滚动效果的可滚动块。可滚动widget,如ListView、GridView等都有对应的Sliver实现如SliverList、SliverGrid等。对于大多数Sliver来说,它们和可滚动Widget最主要的区别是Sliver不会包含Scrollable Widget,也就是说Sliver本身不包含滚动交互模型 ,正因如此,CustomScrollView才可以将多个Sliver"粘"在一起,这些Sliver共用CustomScrollView的Scrollable,最终实现统一的滑动效果。

示例

import 'package:flutter/material.dart';class CustomScrollViewTestRoute extends StatelessWidget {@overrideWidget build(BuildContext context) {//因为本路由没有使用Scaffold,为了让子级Widget(如Text)使用//Material Design 默认的样式风格,我们使用Material作为本路由的根。return Material(child: CustomScrollView(slivers: <Widget>[//AppBar,包含一个导航栏SliverAppBar(pinned: true,expandedHeight: 250.0,flexibleSpace: FlexibleSpaceBar(title: const Text('Demo'),background: Image.asset("./images/avatar.png", fit: BoxFit.cover,),),),SliverPadding(padding: const EdgeInsets.all(8.0),sliver: new SliverGrid( //GridgridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, //Grid按两列显示mainAxisSpacing: 10.0,crossAxisSpacing: 10.0,childAspectRatio: 4.0,),delegate: new SliverChildBuilderDelegate((BuildContext context, int index) {//创建子widget      return new Container(alignment: Alignment.center,color: Colors.cyan[100 * (index % 9)],child: new Text('grid item $index'),);},childCount: 20,),),),//Listnew SliverFixedExtentList(itemExtent: 50.0,delegate: new SliverChildBuilderDelegate((BuildContext context, int index) {//创建列表项      return new Container(alignment: Alignment.center,color: Colors.lightBlue[100 * (index % 9)],child: new Text('list item $index'),);},childCount: 50 //50个列表项),),],),);}
}

代码分为三部分:

  • SliverAppBar:SliverAppBar对应AppBar,两者不同之处在于SliverAppBar可以集成到CustomScrollView。SliverAppBar可以结合FlexibleSpaceBar实现Material Design中头部伸缩的模型,具体效果,读者可以运行该示例查看。
  • SliverGrid:它用SliverPadding包裹以给SliverGrid添加补白。SliverGrid是一个两列,宽高比为4的网格,它有20个子widget。
  • SliverFixedExtentList:它是一个所有子元素高度都为50像素的列表。

转载于:https://www.cnblogs.com/SLchuck/p/10332150.html

08-可滚动Widget相关推荐

  1. 可滚动Widget SingleChildScrollView

    SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子Widget.定义如下: SingleChildScrollView({this.scrollD ...

  2. 深入Flutter(四) Infinite scrolling -- 无限滚动

    文章系列 深入Flutter(一) 积极推进"组合"方式 深入Flutter(二) 线性时间复杂度的 build 和 layout 深入Flutter(三) Element树和Re ...

  3. Flutter键盘弹出造成布局异常解决

      在使用flutter开发时,经常会遇到输入框弹起的时候,debug环境下会提示布局异常.下面我们分两种情况进行讨论分析 输入框在可滚动widget上 输入框如果在滚动的widget上时,键盘弹起, ...

  4. 读书笔记——Flutter实战

    第一章 起步 1.2:初识Flutter 静态编译与动态解释:静态编译的程序在执行前全部被翻译为机器码,通常将这种类型称为AOT (Ahead of time)即 "提前编译":而 ...

  5. OFBIz之旅[结构解析]

    OFBIz之旅[结构] 注意: 1 ,持久层,在 OFBIZ 中的定义,就是 Model . DAO 被划分到业务层中. OFBIz 已经改名为 OpenTaps 项目发展了.其自身的工作流引擎也已经 ...

  6. flutter listview 滚动到底部_Flutter常用Widget详解(三)

    前言 前面两篇文章给大家介绍了Widget中对应原生开发中的一些常用基础控件,Text.TextField.Button.Dialog.Picker等,本篇我们将和大家一起学习ListView.Gri ...

  7. Windows Mobile Widget Emulator

    今天Vimpyboy 在codeplex发布了Windows Mobile Widget Emulator.这是一个用来调试Windows Mobile 6.5 Widget的工具,我在做Window ...

  8. web.xml.jsf_使用JSF 2.2功能来开发可滚动,可延迟加载的Ajax数据表

    web.xml.jsf 这次,我想与您分享我最近从JSF 2.2功能中学到的知识. 为此,我决定创建一个简单的ajax,可滚动,延迟加载的数据表. 请注意, 绝不这是相当大的库如Primefaces ...

  9. 使用JSF 2.2功能来开发可滚动,可延迟加载的Ajax数据表

    这次,我想与您分享我最近从JSF 2.2功能中学到的知识. 为此,我决定创建一个简单的ajax,可滚动的延迟加载数据表. 请注意, 绝不这是相当大的库如Primefaces , RichFaces的或 ...

最新文章

  1. python里的tplt什么意思 Python的format格式化输出
  2. tomcat配置manager
  3. Chrome 控制台console的用法
  4. C++字符串分割替换 ubuntu版本
  5. 国外知名的开源项目托管网站
  6. import oracle utility_教你如何Oracle数据导入
  7. 水文勘测工比赛计算机基本应用,第四届全国水文勘测工大赛内业操作试题A卷.doc...
  8. 【Python】区分List 和String
  9. 从零基础入门Tensorflow2.0 ----七、37. 文本生成之---3. 采样文本生成
  10. 第88课:Spark Streaming从Flume Pull数据案例实战及内幕源码解密
  11. esp8266WIFI模块教程:正点原子ATK-ESP8266进行网络通信,单片机与电脑,单片机与手机发送数据
  12. 腾讯首款区块链AR游戏上线《一起来捉妖》,风物志里的奇珍异兽
  13. 在华为 (Huawei) 工作是怎样一番体验?
  14. 根据经纬度查询具体地址
  15. [django]从前端返回字符串,后端转换为字典,执行数据添加操作
  16. Basic Block
  17. python抓取酷我MV
  18. 国外问卷调查是骗人的吗?
  19. 安卓微信8.0.22 正式版,5个隐秘改变你发现了吗?
  20. Android开发中onClick事件的几种实现,分析,对比

热门文章

  1. (四)训练用于口罩检测的YOLOv5模型
  2. 使用加速度计进行崩溃检测
  3. 使用Keras和CNN进行自定义AI人脸识别
  4. 电子邮件地址验证:详细解释,生产质量WPF文本框代码
  5. 相比 Windows 为什么越来越多人选择Linux?
  6. 顺序图组合片段类型及属性
  7. mysql数据库管理指导_mysql学习笔记一(数据库管理控制)
  8. 怎么把python添加到path_如何将python的路径加到path中
  9. 暴露的全局方法_Dubbo源码解析实战 - 服务暴露原理
  10. python导入模块介绍_详解Python模块导入方法