Flutter基础控件介绍

StatefulWidget

动态组件,开发中需要改变状态,使用动态组件

StatelessWidget

静态组件,定义后不会再改变

组件按照功能分类

1. 基础类组件

基础组件

Text(文本),Image(图片),xxButton(按钮),TextField(输入框),Form(表单)

Text('Hello World');

Form

单独说一下Form组件

​ 实际业务中,在正式向服务器提交数据前,都会对各个输入框数据进行合法性校验,但是对每一个TextField都分别进行校验将会是一件很麻烦的事。还有,如果用户想清除一组TextField的内容,除了一个一个清除有没有什么更好的办法呢?为此,Flutter提供了一个Form widget,它可以对输入框进行分组,然后进行一些统一操作,如输入内容校验、输入框重置以及输入内容保存。

​ Form的子孙元素必须是FormField类型,FormField是一个抽象类,定义几个属性,FormState内部通过它们来完成操作。

详细

2. 布局类组件

Row(水平线性布局),Column(垂直线性布局),Flex(弹性布局),Wrap|Flow(流式布局),Stack|Positioned(层叠布局)

线性布局(Row、Column)

Column(
 crossAxisAlignment: CrossAxisAlignment.start,//子控件对齐方式  mainAxisSize: MainAxisSize.max,    //自身大小  children: <Widget>[],  //子控件 )

弹性布局(Flex)

Flex(
        direction: Axis.horizontal,
        children: <Widget>[
          Expanded(
            child: Container(
              height: 30,
              color: Colors.red,),
            flex: 1,),
          Expanded(
            child: Container(
              height: 30,
              color: Colors.blue,),
            flex: 2,
          ),],),

Flex里面的两个Expanded按照1:2平分。

流式布局(Wrap、Flow)

  • Wrap直接使用,超过屏幕自动换行
  • Flow需要自己算,性能较好,换行规则自己定

Flow因为计算复杂使用较少,优先考虑Wrap是否能实现 详细

层叠布局(Stack、Positioned)

  • Stack类似Android中的FrameLayout,子Widget根据到四个角的位置来确定本身的位置,允许子Widget堆叠。
  • Flutter中联合使用Stack和Positioned来实现绝对定位,Stack允许子Widget堆叠,Positioned可以给子Widget定位。 依据Flutter中的万物皆Widget,所以Positioned这个Widget是一个设置位置的Widget,目的只是给子Widget设置位置。

3. 容器类组件

Padding(添加补白),ConstrainedBox|SizedBox(限制类容器),DecoratedBox(装饰类容器),Transform(变换),Container,其他

​ 布局类Widget和容器类Widget的区别

  1. 布局类Widget一般接收一个Widget数组(children),直接或间接继承自(包含)MultiChildRenderObjectWidget,容器类Widget一般只需要接收一个Widget(child),直接或间接继承自(包含)SingleChildRenderObjectWidget;
  2. 布局类Widget是按照一定的排列方式来对其子Widget进行排列;而容器类Widget一般只是包装其子Widget,对其添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)。

Padding

​ 可以给子节点添加补白,Flutter中给Widget添加间距也单独抽出Widget

限制类容器(ConstrainedBox、SizedBox)

ConstrainedBox用于添加对子Widget的限制

ConstrainedBox(
  constraints: BoxConstraints(//用于设置限制条件     minWidth: double.infinity, //宽度尽可能大     minHeight: 50.0 //最小高度为50像素   ),
  child: Widget,)

SizedBox用于给子Widget指定固定的宽高

SizedBox(
  width: 80.0,
  height: 80.0,
  child: redBox)

装饰容器(DecoratedBox)

const DecoratedBox({
  Decoration decoration,
  DecorationPosition position = DecorationPosition.background,
  Widget child})

使用Decoration的实现类去装饰子Widget(BoxDecoration)

BoxDecoration({
  Color color, //颜色   DecorationImage image,//图片   BoxBorder border, //边框   BorderRadiusGeometry borderRadius, //圆角   List<BoxShadow> boxShadow, //阴影,可以指定多个   Gradient gradient, //渐变   BlendMode backgroundBlendMode, //背景混合模式   BoxShape shape = BoxShape.rectangle, //形状 })

变换(Transform、RotateBox)

​ Transform可以实现4D矩阵变换(Matrix4)、位移(offset)、旋转(rotate)、缩放(scale);

注意:Transform只应用于绘制阶段,不应用于layout阶段,所以无论对子Widget做何种变换,其在屏幕上的位置和占用空间的大小是不会变的

RotateBox和Transform的功能类似,但是它作用于layout阶段,会影响子Widget的位置和占用空间大小。

Container

​ Container是各种DecoratedBox、ConstrainedBox、Transform、Padding、Align等widget的一个组合widget,可以同时实现装饰、变换、限制的功能,

此外margin的补白是在容器外部,而padding的补白是在容器内部

其他 Scaffold

​ Scaffold,由Flutter Material库提供,是一个路由页的骨架,可以非常容易的拼装出一个完整的页面

​ AppBar是一个Material风格的导航栏,它可以设置标题、导航栏菜单、底部Tab等

​ TabBar生成一个静态的菜单,TabBarView配合TabBar实现左右切换的View,抽屉菜单Drawer,FloatingActionButton悬浮在页面的某一个位置作为某种常用动作的快捷入口

4.可滚动Widget

SingleChildScrollView,ListView,GridView,CustomScrollView,滚动监听和控制ScrollController。

​ 当内容超过显示窗口(ViewPort)的时候,Flutter就会提示Overflow错误,因此需要滚动Widget,可滚动的Widget都直接或者间接包含Scrollable widget。

SingleChildScrollView

​ 类似Android中的ScrollView,只接收一个子Widget

ListView

ListView最常用的可滚动widget

ListView({
  ...  
  //可滚动widget公共参数   Axis scrollDirection = Axis.vertical,//滚动方向   bool reverse = false,//是否反向(从右到左)   ScrollController controller,//控制滚动位置和监听滚动事件   bool primary,//是否使用Widget树中默认的PrimaryScrollController   ScrollPhysics physics,//接收一个ScrollPhysics参数   EdgeInsetsGeometry padding,
  //ListView各个构造函数的共同参数   double itemExtent,//强制item的高度,相对不设置会高效   bool shrinkWrap = false,
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double cacheExtent,
  //子widget列表   List<Widget> children = const <Widget>[],
})

physics:决定可滚动widget怎样响应用户的操作,比如滑动完抬起手指,或滑动到边界时如何显示

  • ClampingScrollPhysics:Android下微光效果。
  • BouncingScrollPhysics:iOS下弹性效果。

​ addAutomaticKeepAlives:是否将列表项(子Widget)包裹在AutomaticKeepAlive widget中,典型的,在一个懒加载列表中,如果列表项包裹在AutomaticKeepAlive中,列表项移出视口时该列表项不会GC,会使用KeepAliveNotification来保存其状态。如果列表项自己维护KeepAlive状态,则此项为false。 addRepaintBoundaries:是否将列表项(子Widget)包裹在RepaintBoundary中。将列表项包裹在RepaintBoundary中可以避免在滚动的时候重绘,但重绘开销非常小的时候,不添加RepaintBoundary反而会高效。 ListView 的构造函数 默认构造函数

ListView(
  shrinkWrap: true, 
  padding: const EdgeInsets.all(20.0),
  children: <Widget>[
    const Text("Im dedicating every day to you"),
    const Text("Domestic life was never quite my style"),
    const Text("When you smile, you knock me out, I fall apart"),
    const Text("And I thought I was so smart"),
  ],);

默认构造函数会把所有的子widget提前创建好。

ListView.builder构造函数

ListView.builder({
  // ListView公共参数已省略   ...
  @required IndexedWidgetBuilder itemBuilder, //列表的构造器,返回一个Widget   int itemCount,//列表项的数量,null表示无限   ...})

ListView.separated构造函数

​ 比ListView.build多一个separatorBuilder,用于生成分割线。

GridView

​ 基本和ListView相同,有个一SliverGridDelegate gridDelegate参数,用于控制子widget如何排列。 两个实现类: ​ SliverGridDelegateWithFixedCrossAxisCount 横轴为固定数量子元素, ​ SliverGridDelegateWithMaxCrossAxisExtent 横轴子元素为固定最大长度的layout算法。

默认构造函数 GridView({})

GridView.count构造函数

​ 内部使用SliverGridDelegateWithFixedCrossAxisCount去创建横轴为固定数量的GridView。

GridView.extent构造函数

​ 内部使用了SliverGridDelegateWithMaxCrossAxisExtent去创建横轴子元素为固定最大长度的算法。

GridView.builder构造函数

GridView.builder(
 ...
 @required SliverGridDelegate gridDelegate, 
 @required IndexedWidgetBuilder itemBuilder, //子widget构造方法 )

Pub上有一个包“flutter_staggered_grid_view” ,它实现了一个交错GridView的布局,子widget大小不一样。

CustomScrollView

​ CustomScrollView是可以使用Sliver自定义滚动模型(效果)的widget。CustomScrollView可以把彼此独立的可滚动的widget(Sliver)“粘”起来。

​ 可滚动的widget如ListView,GridView都有对应的Sliver实现SliverList,SliverGrid。对于大多数Sliver来说,他们和可滚动的widget的区别是Sliver不包含Scrollable widget,本身Sliver不包含滚动模型,这些widget公用CustomScrollView的Scrollable,最终实现统一滚动效果。

详细

滚动监听及控制ScrollController

​ 可以通过ScrollController来控制Scrollable widget的滚动位置,滚动事件传递等。

ScrollController构造函数

ScrollController({
    double initialScrollOffset = 0.0, //初始滚动位置     this.keepScrollOffset = true,   //是否保存滚动位置 })

​ 常用方法和属性offset:可滚动组件当前滚动的位置;jumpTo(double offset)、animateTo(double offset) 跳转到指定位置。

滚动监听

ScrollController间接继承自Listenable,可以监听滚动事件

controller.addListener(()=>print(controller.offset));

滚动位置恢复

​ PageStorage是用于保存页面(路由)相关数据的Widget,是一个功能型widget,不影响子树的UI外观,它拥有一个存储桶(bucket),子树中的widget可以通过指定不同的PageStorageKey来存储各自的数据或状态。

​ 需要配合keepScrollOffset使用,为true的时候,会记录滚动位置。

​ 当一个路由中包括多个Scrollable widget的时候,在进行一些跳转操作后,滚动位置不能正确恢复,这时可以显式给Scrollable widget指定PageStoreKey来分别跟踪。

并非一个路由包含多个Scrollable widget时,就需要使用PageStoreKey分别跟踪,因为它们都是StatefullWidget,只要widget没有被从树上detach掉,其state就不会销毁(dispose),滚动位置就不会丢失。

ScrollPosition

​ ScrollController可以被多个Scrollable widget使用,ScrollController会为每个Scrollable widget创建一个ScrollPosition,这些ScrollPosition保存在ScrollController的position中。ScrollPosition是真正保存滑动位置信息的对象,offset只是一个便捷属性。

ScrollPosition有animateTo(),jumpTo(),来控制真正跳转滚动位置的方法,ScrollController的两个同名方法,最终会调用这两个。

滚动监听

​ Flutter widgets树中的子widget可以通过发送通知与父(包括祖)widget通信,父widget也可以通过NotificationListener widget来监听自己关注的通知。

​ NotificationListener是一个widget,模板参数是想要关注的通知类型,如果省略,则所有类型的通知都会监听。需要实现一个onNotification回调函数,实现监听处理逻辑,返回布尔值,如果返回true,则事件停止向上传递,返回false则继续向上传递。

5.功能型widget

​ 功能性widget是指不会影响UI布局及外观的widget,通常有一定功能,如事件监听,数据存储等。

导航事件拦截(WillPopScope)

​ 通过WillPopScope实现返回按钮拦截,包括Android的物理返回键和导航返回按钮。在onWillPop回调函数中处理相关逻辑,返回true时当前路由出栈,返回false时,当前路由不出栈。

数据共享(InheritedWidget)

​ 可以高效的将数据在widget树中下传递、共享。例如正是通过InheritedWidget来共享Theme(主题)和Locale(当前语言环境)信息。

主题(Theme)

​ Theme widget可以为Material App定义主题数据(ThemeData),Material组件库里很多Widget都使用了主题数据,如导航栏颜色、标题字体、Icon样式等。Theme会通过InheritedWidget来为其子树widget共享样式数据。

​ 可定义的主题数据都在ThemeData中,可以通过Theme.of(context)获取当前的ThemeData。

更多更新关注微信公众号“Flutter入门”

《Flutter基础控件介绍》
Flutter入门

    原文作者:马大猛
    原文地址: https://zhuanlan.zhihu.com/p/61613340
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞