前提:从事开发已经十年了,PC开发/Android开发/后端开发,初级/中级/高级/架构师,成员/组长/开发负责人,以及各种考证和阶段目标计划…,一路走来喜怒哀乐/酸甜苦辣都体验了。

人无远虑必有近忧,千里之行始于足下,今天为近一段时间学习flutter进行小结,为预定的企业级项目做准备(要求生产环境 10万用户以上)。

1,flutter 原理(后期会计划分析源码,进而深入理解原理)

flutter 是谷歌推出的应用开发UI框架,它提供了绘图的各种Api和组件,如图:

flutter 已支持移动、Web、桌面和嵌入式设备,这意味着它正式成为了支持多平台的轻量级 UI 框架

1,相关管理

资源:flutter app安装包中会包含代码和 assets(资源)两部分。Assets是会打包到程序安装包中的,可在运行时访问。常见类型的assets包括静态数据(例如JSON文件)、配置文件、图标和图片(JPEG,WebP,GIF,动画WebP / GIF,PNG,BMP和WBMP)等。

flutter:assets:- graphics/background.png

包:Pub(https://pub.dev/ )是谷歌官方的Dart Packages仓库,flutter使用配置文件pubspec.yaml(位于项目根目录)来管理第三方依赖包。

dependencies:flutter:sdk: fluttercupertino_icons: ^0.1.2dev_dependencies:flutter_test:sdk: flutterflutter:uses-material-design: true

路由:所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。

//导航到新路由   Navigator.push( context,MaterialPageRoute(builder: (context) {return NewRoute();}));},//退出
Navigator.pop(context, "我是返回值"),

2,相关组件(属性+缩略图)

Widget、Element、RenderObject

Widget实际上就是Element的配置数据,一个Widget对象可以对应多个Element对象,从创建到渲染的大体流程是:根据Widget生成Element,然后创建相应的RenderObject并关联到Element.renderObject属性上,最后再通过RenderObject来完成布局排列和绘制。如图:

StatefulWidget

abstract class StatefulWidget extends Widget {@overrideStatefulElement createElement() => StatefulElement(this);@protectedState createState();
}StatefulWidget对Flutter开发者来讲非常熟悉了。
createElement方法返回的是一个StatefulElement实例。方法createState()构建对应于这个StatefulWidget的State。
StatefulWidget没有生成RenderObject的方法。
所以StatefulWidget也只是个中间层,它需要对应的State实现build方法来返回子Widget。

StatelessWidget

abstract class StatelessWidget extends Widget {/// Initializes [key] for subclasses.const StatelessWidget({ Key key }) : super(key: key);@overrideStatelessElement createElement() => StatelessElement(this);@protectedWidget build(BuildContext context);
}StatelessWidget对Flutter开发者来讲再熟悉不过了。它的createElement方法返回的是一个StatelessElement实例。
StatelessWidget没有生成RenderObject的方法。所以StatelessWidget只是个中间层,它需要实现build方法来返回子Widget。

基础组件-〉

Text (文本)

class Text extends StatelessWidget {const Text(this.data, {Key key,this.style, //字体的样式设置this.textAlign,  //文本对齐方式(center居中,left左对齐,right右对齐,justfy两端对齐)this.textDirection, //文本方向(ltr从左至右,rtl从右至左)this.locale,  //本地语言类型this.softWrap, //是否自动换行(true自动换行,false单行显示,超出屏幕部分默认截断处理)this.overflow, //文字超出屏幕之后的处理方式(clip裁剪,fade渐隐,ellipsis省略号)this.textScaleFactor,this.maxLines, //文字显示最大行数this.semanticsLabel, //字体显示倍率}) : assert(data != null),textSpan = null,super(key: key);...
}

Button 按钮系列

RaisedButton 即"漂浮"按钮,它默认带有阴影和灰色背景。按下后,阴影会变大。
FlatButton即扁平按钮,默认背景透明并不带阴影。按下后,会有背景色。
OutlineButton默认有一个边框,不带阴影且背景透明。按下后,边框颜色会变亮、同时出现背景和阴影(较弱)。
IconButton是一个可点击的Icon,不包括文字,默认没有背景,点击后会出现背景。
RaisedButton、FlatButton、OutlineButton都有一个icon 构造函数,通过它可以轻松创建带图标的按钮。
ButtonBar :按钮组
FloatingActionButton :浮动按钮属性名称       值类型         属性值
onPressed   VoidCallback    必填参数,按下按钮时触发的回调,接收一个 方法,传 null 表示按钮禁用,会显示禁用相关 样式
child       Widget          文本控件
color       Color           按钮的颜色
disabledColor   Color       按钮禁用时的颜色
disabledTextColor   Color   按钮禁用时的文本颜色
splashColor         Color   点击按钮时水波纹的颜色
highlightColor      Color   点击(长按)按钮后按钮的颜色
elevation           double  阴影的范围,值越大阴影范围越大
padding                     内边距
shape                       设置按钮的形状
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
)
shape: CircleBorder(
side: BorderSide( color: Colors.white )
)/**const FloatingActionButton({Key key,this.child,//按钮显示的内容this.tooltip,//长按时显示的提示this.foregroundColor,//前景色,影响到文字颜色this.backgroundColor,//背景色this.heroTag = const _DefaultHeroTag(),//hero效果使用的tag,系统默认会给所有FAB使用同一个tag,方便做动画效果this.elevation = 6.0,//未点击时阴影值this.highlightElevation = 12.0,//点击下阴影值@required this.onPressed,this.mini = false,//FloatingActionButton有regular, mini, extended三种类型,默认为false即regular类型,true时按钮变小即mini类型,extended需要通过FloatingActionButton.extended()创建,可以定制显示内容this.shape = const CircleBorder(),//定义FAB的shape,设置shape时,默认的elevation将会失效,默认为CircleBorderthis.clipBehavior = Clip.none,this.materialTapTargetSize,this.isExtended = false,//是否为”extended”类型})*/

Image (图片/图标Icon)

Image:通过ImageProvider来加载图片
Image.asset:用来加载本地资源图片
Image.file:用来加载本地(File文件)图片
Image.network:用来加载网络图片
Image.memory:用来加载Uint8List资源(byte数组)图片 new Image(image: new AssetImage('images/logo.png'));new Image(image: new NetworkImage('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'))new Image.asset('images/logo.png')new Image.file(new File('/storage/xxx/xxx/test.jpg'))new Image.network('http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg')new FadeInImage.assetNetwork(placeholder: 'images/logo.png',image: imageUrl,width: 120,fit: BoxFit.fitWidth,
)new FadeInImage.memoryNetwork(placeholder: kTransparentImage,image: imageUrl,width: 120,fit: BoxFit.fitWidth,
)new CachedNetworkImage(width: 120,fit: BoxFit.fitWidth,placeholder: new CircularProgressIndicator(),imageUrl: imageUrl,errorWidget: new Icon(Icons.error),
)new Image.memory(bytes)

Switch和Checkbox (单选框/复选框)

const Switch({Key key,@required this.value,    //true:开, false:关@required this.onChanged,   //状态变化时的回调方法this.activeColor,   //打开状态下颜色this.activeTrackColor,   //打开状态下track颜色this.inactiveThumbColor,   //关闭状态thumb颜色this.inactiveTrackColor,   //关闭状态track颜色this.activeThumbImage,   //打开状态下thumb图片this.inactiveThumbImage,   //关闭状态下thumb图片this.materialTapTargetSize,   //点击区域
}) const Checkbox({Key key,@required this.value, //是否选中此复选框this.tristate = false, //默认false,如果为true,复选框的值可以为true、false或null。@required this.onChanged, //监听 当复选框的值应该更改时调用this.activeColor, //选中此复选框时要使用的颜色this.checkColor, //选中此复选框时用于复选图标的颜色this.materialTapTargetSize, //为目标与布局大小,默认有 padded 和 shrinkWrap 两种状态;小菜理解 padded 为谷歌设计建议尺寸 48px * 48px,shrinkWrap 为目标尺寸缩小到谷歌设计提供的最小值,但在实际效果中差别不大})

TextField (输入框和表单)

const TextField({Key key,this.controller,            //控制器,控制TextField文字this.focusNode,this.decoration: const InputDecoration(),      //输入器装饰TextInputType keyboardType: TextInputType.text, //输入的类型this.style,this.textAlign: TextAlign.start,this.autofocus: false,this.obscureText: false,  //是否隐藏输入this.autocorrect: true,this.maxLines: 1,this.maxLength,this.maxLengthEnforced: true,this.onChanged,            //文字改变触发this.onSubmitted,          //文字提交触发(键盘按键)this.onEditingComplete,  //当用户提交可编辑内容时调用this.inputFormatters,this.enabled,this.cursorWidth = 2.0,this.cursorRadius,this.cursorColor,this.keyboardAppearance,})

布局组件->

Row、Column (线性布局)

/*** 行布局** Row({Key key,//mainAxisAlignment主轴上的对齐方式//center:将children放置在主轴的中心;//end:将children放置在主轴的末尾;//spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾空白区域为children之间的1/2;//spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾没有空白区域;//spaceEvenly:将主轴方向上的空白区域均分,使得children之间和收尾的空白区域相等;//start:将children放置在主轴的起点;MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,MainAxisSize mainAxisSize = MainAxisSize.max,//控住一行的高度,max:最大化主轴方向的可用空间;min:与max相反,是最小化主轴方向的可用空间;CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,//交叉轴上的对齐方式,baseline:children在交叉轴方向,根据baseline对齐,stretch:让children填满交叉轴方向,start,center,end.TextDirection textDirection,//阿拉伯语系的兼容设置,一般无需处理VerticalDirection verticalDirection = VerticalDirection.down,//定义了children摆放顺序,down:从left到right进行布局,up:从right到left进行布局TextBaseline textBaseline,List<Widget> children = const <Widget>[],})*//*** 列布局** Column({Key key,//mainAxisAlignment主轴上的对齐方式//center:将children放置在主轴的中心;//end:将children放置在主轴的末尾;//spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾空白区域为children之间的1/2;//spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾没有空白区域;//spaceEvenly:将主轴方向上的空白区域均分,使得children之间和收尾的空白区域相等;//start:将children放置在主轴的起点;MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,//控住一行的高度,max:最大化主轴方向的可用空间;min:与max相反,是最小化主轴方向的可用空间;MainAxisSize mainAxisSize = MainAxisSize.max,//交叉轴上的对齐方式,baseline:children在交叉轴方向,根据baseline对齐,stretch:让children填满交叉轴方向,start,center,end.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,TextDirection textDirection,//阿拉伯语系的兼容设置,一般无需处理//定义了children摆放顺序,down:从top到bottom进行布局,up:从bottom到top进行布局VerticalDirection verticalDirection = VerticalDirection.down,TextBaseline textBaseline,List<Widget> children = const <Widget>[],})**/

Flex (弹性布局)

Flex({...@required this.direction, //弹性布局的方向, Row默认为水平方向,Column默认为垂直方向List<Widget> children = const <Widget>[],
})

Expanded (扩充布局)

const Expanded({int flex = 1, @required Widget child,
})

Wrap、Flow (流式布局)

/**Wrap({Key key,this.direction = Axis.horizontal,//主轴(mainAxis)的方向,默认为水平。this.alignment = WrapAlignment.start,//主轴方向上的对齐方式,默认为start。this.spacing = 0.0,//主轴方向上的间距。this.runAlignment = WrapAlignment.start,//run的对齐方式。run可以理解为新的行或者列,如果是水平方向布局的话,run可以理解为新的一行。this.runSpacing = 0.0,//run的间距。this.crossAxisAlignment = WrapCrossAlignment.start,//交叉轴(crossAxis)方向上的对齐方式。this.textDirection,//文本方向。this.verticalDirection = VerticalDirection.down,//定义了children摆放顺序,默认是down,见Flex相关属性介绍。List<Widget> children = const <Widget>[],//})*//*** 一般用在流式布局中,比如标签,瀑布流等Flow({Key key,@required this.delegate,//绘制子viewList<Widget> children = const <Widget>[],})*/

Stack、Positioned(层叠布局)

Stack({Key key,this.alignment = AlignmentDirectional.topStart, //指的是子Widget的对其方式,默认情况是以左上角为开始点 。this.textDirection,this.fit = StackFit.loose, //用来决定没有Positioned方式时候子Widget的大小,StackFit.loose 指的是子Widget 多大就多大,StackFit.expand使子Widget的大小和父组件一样大this.overflow = Overflow.clip, 指子Widget 超出Stack时候如何显示,默认值是Overflow.clip,子Widget超出Stack会被截断,Overflow.visible超出部分还会显示的List<Widget> children = const <Widget>[],
})const Positioned({Key key,this.left,this.top,this.right,this.bottom,this.width,this.height,@required Widget child,
})left、top 、right、 bottom分别代表离Stack左、上、右、底四边的距离。
width和height用于指定需要定位元素的宽度和高度。
注意,Positioned的width、height 和其它地方的意义稍微有点区别,
此处用于配合left、top 、right、 bottom来定位组件,
举个例子,在水平方向时,你只能指定left、right、width三个属性中的两个,
如指定left和width后,right会自动算出(left+width),
如果同时指定三个属性则会报错,垂直方向同理。

IndexedStack

IndexedStack({Key key,AlignmentGeometry alignment = AlignmentDirectional.topStart,TextDirection textDirection,StackFit sizing = StackFit.loose,this.index = 0,List<Widget> children = const <Widget>[],})1.IndexedStack和Stack一样,都可以在一个组件上面放置另一个组件,唯一不同的是IndexedStack只能同时显示子组件中的一个组件,并通过Index属性来设置要显示的控件
2.alignment: 设置子组件在Stack中的对齐方式
3.index: 要显示的子组件的下标,对应children的List的下标
4.textDirection:设置子组件在Stack中从左往右排列,还是从右往左排列
5.sizing:调整IndexedStack组件中的没有使用Position包裹的子组件的宽高
loose: 子组件的宽高从Stack约束的最小值到最大值之间取值
expand: 子组件的宽高取Stack约束的最大值
passthrough:从父组件传递到Stack组件的约束将不加修改地传递给Stack组件中没有被Position组件包裹的子组件

SizedBox (宽高尺寸处理)

/*** 能强制子控件具有特定宽度、高度或两者都有,使子控件设置的宽高失效* const SizedBox({* Key key,* this.width,* this.height,* Widget child* })* */

ConstrainedBox (限定最大最小宽高布局)

/*** 限制子元素的最大最小宽高* ConstrainedBox({Key key,@required this.constraints,//限制条件Widget child})*/
/***const BoxConstraints({this.minWidth = 0.0,this.maxWidth = double.infinity,this.minHeight = 0.0,this.maxHeight = double.infinity})*/

LimitedBox (限定最大宽高布局)

LimitedBox组件是当不受父组件约束时限制它的尺寸,什么叫不受父组件约束?就像这篇文章介绍的其他组件,它们都会对子组件约束,没有约束的父组件有ListView、Row、Column等,如果LimitedBox的父组件受到约束,此时LimitedBox将会不做任何操作,我们可以认为没有这个组件,代码如下:

Container(height: 100,width: 100,child: LimitedBox(maxHeight: 50,maxWidth: 100,child: Container(color: Colors.green,),),
)

AspectRatio (调整宽高比)

/*** 强制子部件的宽度和高度具有给定的宽高比,可以父容器给定一个宽或者高,来换算另一个值const AspectRatio({Key key,@required this.aspectRatio,//宽高比Widget child})* */

FractionallySizedBox (百分比布局)

/*** 百分比布局,SizeBox直接通过width,height限制子控件;FractionallySizedBox通过百分比限制* const FractionallySizedBox({Key key,this.alignment = Alignment.center,this.widthFactor,//宽度因子,乘以宽度就是组件最后的宽this.heightFactor,Widget child,})*/

Baseline

const Baseline({Key key,@required this.baseline,@required this.baselineType,Widget child,})1.baseline:子组件基准线距离顶部的距离
2.baselineType
TextBaseline.alphabetic:对齐字母字符的字形底部的水平线
TextBaseline.ideographic:对齐表意文字的水平线

Offstage (是否可见)

/*** 控制child是否显示*当offstage为true,控件隐藏; 当offstage为false,显示;当Offstage不可见的时候,如果child有动画等,需要手动停掉,Offstage并不会停掉动画等操作。const Offstage({ Key key, this.offstage = true, Widget child })*/

Opacity

/**     设置子控件透明度const Opacity({Key key,@required this.opacity,//透明度,0.0 到 1.0,0.0表示完全透明,1.0表示完全不透明this.alwaysIncludeSemantics = false,Widget child,})*/

DecoratedBox(装饰盒子)

/*** 在子控件绘制之前或之后绘制一个装饰const DecoratedBox({Key key,@required this.decoration,//要绘制的装饰器this.position = DecorationPosition.background,//绘制在子组件上面(DecorationPosition.background)还是下面(DecorationPosition.foreground)Widget child})*/

RotatedBox (旋转盒子)

/***  旋转组件*   const RotatedBox({Key key,@required this.quarterTurns,//旋转的次数,每次旋转的度数只能是90度的整数倍Widget child,})*/

Align (对齐与相对定位)

const Align({Key key,this.alignment = Alignment.center,this.widthFactor,this.heightFactor,Widget child,
})alignment : 需要一个AlignmentGeometry类型的值,表示子组件在父组件中的起始位置。AlignmentGeometry 是一个抽象类,它有两个常用的子类:Alignment和 FractionalOffset,我们将在下面的示例中详细介绍。
widthFactor和heightFactor是用于确定Align 组件本身宽高的属性;它们是两个缩放因子,会分别乘以子元素的宽、高,最终的结果就是Align 组件的宽高。如果值为null,则组件的宽高将会占用尽可能多的空间。

FittedBox 缩放布局

const FittedBox({Key key,this.fit = BoxFit.contain,this.alignment = Alignment.center, //child对齐方式Widget child,})fit 即child的缩放方式,比如以下缩放方式:
fill(通过扭曲源的纵横比填充目标框。)
contain(尽可能大,同时仍然将源完全包含在目标框中)
cover(尽可能小,同时仍然覆盖整个目标框)
fitWidth(确保显示了源的全部宽度,不管这是否意味着源垂直地溢出目标框)
fitHeight(确保显示源的完整高度,不管这是否意味着源水平地溢出目标框)
none(将源文件对齐到目标框内(默认情况下居中),并丢弃位于框外的源文件的任何部分。
源映像没有调整大小。
scaleDown(将源文件对齐到目标框内(默认情况下,居中),如果需要,将源文件向下缩放,以确保源文件适合框内,这与contains相同,如果它会收缩图像,则它与none相同)

容器->

Container (容器)

Container({Key key,this.alignment,//控制child的对齐方式this.padding, //设置内边距Color color, //设置背景颜色Decoration decoration,//绘制在child下层的装饰,不能与color同时使用this.foregroundDecoration,//绘制在child上层的装饰double width, //宽double height, //高BoxConstraints constraints,添加到child上额外的约束条件this.margin,//外边距this.transform,//设置container的变换矩阵,类型为Matrix4this.child, //子组件})/** 装饰器,可以用来修饰其他的组件,和Android里面的shape很相似const BoxDecoration({this.color,//背景色this.image,//图片this.border,//描边this.borderRadius,//圆角大小this.boxShadow,//阴影this.gradient,//过度效果this.backgroundBlendMode,this.shape = BoxShape.rectangle,//形状,BoxShape.circle和borderRadius不能同时使用})*/

Padding(填充)

const Padding({Key key,@required this.padding, //padding 值, EdgeInsetss 设置填充的值Widget child, //子组件
})EdgeInsets
fromLTRB(double left, double top, double right, double bottom):分别指定四个方向的填充。
all(double value) : 所有方向均使用相同数值的填充。
only({left, top, right ,bottom }):可以设置具体某个方向的填充(可以同时指定多个方向)。
symmetric({ vertical, horizontal }):用于设置对称方向的填充,vertical指top和bottom,horizontal指left和right。

ConstrainedBox( 尺寸限制类容器)

/*** 限制子元素的最大最小宽高* ConstrainedBox({Key key,@required this.constraints,//限制条件Widget child})*/
/***const BoxConstraints({this.minWidth = 0.0,this.maxWidth = double.infinity,this.minHeight = 0.0,this.maxHeight = double.infinity})*/

Transform(变换)

const Transform({Key key,@required this.transform,this.origin,this.alignment,this.transformHitTests = true,Widget child,})1.对子组件做平移、旋转、缩放变换
2.origin: 指定子组件做平移、旋转、缩放时的中心点 origin: Offset(50, 50)
3.alignment:控制子组件在Transform中的对齐方式
4.transformHitTests:点击区域是否也做相应的变换,为true时执行相应的变换,为false不执行
5.transform:控制子组件的平移、旋转、缩放、倾斜变换

Clip(剪裁)

const ClipOval({ Key key, this.clipper, this.clipBehavior = Clip.antiAlias, Widget child }) : super(key: key, child: child);const ClipRRect({Key key,this.borderRadius,this.clipper,this.clipBehavior = Clip.antiAlias,Widget child,}) : assert(borderRadius != null || clipper != null),assert(clipBehavior != null),super(key: key, child: child);const ClipRect({ Key key, this.clipper, this.clipBehavior = Clip.hardEdge, Widget child }) : super(key: key, child: child);ClipOval    子组件为正方形时剪裁为内贴圆形,为矩形时,剪裁为内贴椭圆(圆形裁剪)
ClipRRect   将子组件剪裁为圆角矩形(圆角矩形裁剪),用borderRadius控制圆角的位置大小
ClipRect    剪裁子组件到实际占用的矩形大小(溢出部分剪裁)(矩形裁剪),需要自定义clipper属性才能使用,否则没效果。自定义clipper并继承CustomClipper类,重写getClip、shouldReclip
ClipPath    路径裁剪。自定义的范围很广。采用了矢量路径path,将组件裁剪成任意形状。和ClipRect一样,需要自定义clipper并继承CustomClipper类,重写getClip、shouldReclip。这里的path用法是和android中自定义view的path是一样的。

滚动组件->

SingleChildScrollView

const SingleChildScrollView({Key key,//滚动方向,默认是垂直方向this.scrollDirection = Axis.vertical,//是否按照阅读方向相反的方向滑动this.reverse = false,//内容边距this.padding,//是否使用widget树中默认的PrimaryScrollControllerbool primary,//此属性接受一个ScrollPhysics类型的对象,它决定可以滚动如何响应用户操作,比如用户滑动完抬起手指后,继续执行动画,或者滑动到边界时,如何显示。//默认情况下,Flutter会根据具体平台分别使用不同的ScrollPhysics对象,对应不同的显示效果,如当滑动到边界时,继续拖动的话,在iOS上会出现弹性效果,//而在Android上会出现微光效果。如果你想在所有平台下使用同一种效果,可以显示指定一个固定的ScrollPhysics。//Flutter SDK包含两个ScrollPhysics的子类。1.ClampingScrollPhysics:Android下微光效果,2.BouncingScrollPhysics:iOS下弹性效果this.physics,//此属性接收一个ScrollController对象,ScrollController的主要作用是控制滚动位置和监听滚动事件。//默认情况下,Widget树中会有一个默认的PrimaryScrollController,如果子树中的可滚动组件没有显示的指定controller,并且primary属性值为true时,可滚动组件会使用这个默认的ScrollController。//这种机制带来的好处是父组件可以控制子树中可滚动的滚动行为,例:scaffold正是使用这种机制在iOS中实现了点击导航回到顶部的功能。this.controller,this.child,
})

ListView

ListView({Key key,Axis scrollDirection = Axis.vertical, //ListView 的方向,为 Axis.vertical 表示纵向,为 Axis.horizontal 表示横向。bool reverse = false, //是否反向滚动ScrollController controller, //滑动监听,值为一个 ScrollController 对象,这个属性应该可以用来做下拉刷新和上垃加载bool primary,//是否是与父级PrimaryScrollController关联的主滚动视图。如果primary为true,controller必须设置ScrollPhysics physics,// 设置 ListView 如何响应用户的滑动行为,值为一个 ScrollPhysics 对象,它的实现类常用的有:AlwaysScrollableScrollPhysics:总是可以滑动。NeverScrollableScrollPhysics:禁止滚动。BouncingScrollPhysics:内容超过一屏,上拉有回弹效果。ClampingScrollPhysics:包裹内容,不会有回弹,感觉跟                 AlwaysScrollableScrollPhysics 差不多。bool shrinkWrap = false, //多用于嵌套listView中 内容大小不确定 比如 垂直布局中 先后放入文字 listView (需要Expend包裹否则无法显示无穷大高度 但是需要确定listview高度 shrinkWrap使用内容适配不会有这样的影响)EdgeInsetsGeometry padding, //滚动视图与子项之间的内边距this.itemExtent, //子项范围bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,bool addSemanticIndexes = true,double cacheExtent,List<Widget> children = const <Widget>[],int semanticChildCount,})适用场景
已知有限个Item的情况下ListView.builder({Key key,Axis scrollDirection = Axis.vertical,//滚动方向,纵向或者横向bool reverse = false,//反转ScrollController controller,//bool primary,//ScrollPhysics physics,bool shrinkWrap = false,EdgeInsetsGeometry padding,this.itemExtent,@required IndexedWidgetBuilder itemBuilder,int itemCount,   //子 Item 数量,只有使用 new ListView.builder() 和 new ListView.separated() 构造方法的时候才能指定,其中 new ListView.separated() 是必须指定。bool addAutomaticKeepAlives = true, //对应于 SliverChildBuilderDelegate.addAutomaticKeepAlives属性。即是否将每个子项包装在AutomaticKeepAlive中。bool addRepaintBoundaries = true, //对应于 SliverChildBuilderDelegate.addRepaintBoundaries属性。是否将每个子项包装在RepaintBoundary中bool addSemanticIndexes = true, //对应于 SliverChildBuilderDelegate.addSemanticIndexes属性。是否将每个子项包装在IndexedSemantics中。double cacheExtent, //视口在可见区域之前和之后有一个区域,用于缓存在用户滚动时即将变为可见的项目。int semanticChildCount,  //提供语义信息的孩子的数量})适用场景 
长列表时采用builder模式,能提高性能。不是把所有子控件都构造出来,而是在控件viewport加上头尾的cacheExtent这个范围内的子Item才会被构造。在构造时传递一个builder,按需加载是一个惯用模式,能提高加载性能。ListView.separated({Key key,Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,bool shrinkWrap = false,EdgeInsetsGeometry padding,@required IndexedWidgetBuilder itemBuilder,@required IndexedWidgetBuilder separatorBuilder,@required int itemCount,bool addAutomaticKeepAlives = true,bool addRepaintBoundaries = true,bool addSemanticIndexes = true,double cacheExtent,}) 适用场景: 列表中需要分割线时,可以自定义复杂的分割线  const ListView.custom({Key key,Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,bool shrinkWrap = false,EdgeInsetsGeometry padding,this.itemExtent,@required this.childrenDelegate,double cacheExtent,int semanticChildCount,})适用场景:上面几种模式基本可以满足业务需求,如果你还想做一些其它设置(如列表的最大滚动范围)或获取滑动时每次布局的子Item范围,可以尝试custom模式

GridView (9宫格布局)

/**GridView({Key key,Axis scrollDirection = Axis.vertical,//滚动方向bool reverse = false,//是否反向显示数据ScrollController controller,bool primary,ScrollPhysics physics,//物理滚动bool shrinkWrap = false,EdgeInsetsGeometry padding,@required this.gridDelegate,bool addAutomaticKeepAlives = true,//自动保存视图缓存bool addRepaintBoundaries = true,//添加重绘边界bool addSemanticIndexes = true,double cacheExtent,List<Widget> children = const <Widget>[],int semanticChildCount,})*/
/**const SliverGridDelegateWithFixedCrossAxisCount({@required this.crossAxisCount,//每行几个this.mainAxisSpacing = 0.0,//主轴方向间距this.crossAxisSpacing = 0.0,//纵轴方向间距this.childAspectRatio = 1.0,//主轴纵轴缩放比例})*/

CustomScrollView

const CustomScrollView({Key key,Axis scrollDirection = Axis.vertical,bool reverse = false,ScrollController controller,bool primary,ScrollPhysics physics,bool shrinkWrap = false,Key center,double anchor = 0.0,double cacheExtent,this.slivers = const <Widget>[],int semanticChildCount,DragStartBehavior dragStartBehavior = DragStartBehavior.start,})// 头部可伸缩widget,屏幕向下滑动时SliverAppBar会自动收缩到一定高度。
SliverAppBar({Key key,this.leading, // 左上方图标this.automaticallyImplyLeading = true,this.title, // 标题this.actions, // 右侧图标组this.flexibleSpace, // 设置内容,背景、标题等this.bottom,this.elevation, // 阴影范围this.forceElevated = false, // 是否一致显示阴影,false在展开时不显示阴影this.backgroundColor, // 背景色this.brightness,this.iconTheme, // 图标样式this.actionsIconTheme, // 右上角图标样式this.textTheme,this.primary = true,this.centerTitle, // 标题是否居中this.titleSpacing = NavigationToolbar.kMiddleSpacing, // 标题距离左侧距离this.expandedHeight, // 展开高度this.floating = false, // 收缩后是否显示顶部标题栏this.pinned = false, // 收缩时是否固定到一定高度this.snap = false, this.shape, // 边框设置})

ScrollController(滚动监听及控制)

ScrollController({
double initialScrollOffset = 0.0,// 初始的偏移量
this.keepScrollOffset = true,//是否保存滚动位置
this.debugLabel,
})animateTo(),滚动到指定位置,可以设置目标偏移量,时间和滚动曲线
jumpTo(),滚动到指定位置,瞬间移动
addListener(), 添加滚动的监听,可以获取滚动过的位置。
dispose(),在widget的dispose时调用,避免内存泄漏

功能组件->

WillPopScope (导航返回拦截)

/***  导航返回拦截,避免用户误触返回按钮而导致APP退出,常用的双击退出功能* const WillPopScope({Key key,@required this.child,@required this.onWillPop,//当用户点击返回按钮时调用(包括导航返回按钮及Android物理返回按钮),返回 Future.value(false); 表示不退出;返回 Future.value(true); 表示退出.})*/

InheritedWidget (数据共享)

abstract class InheritedWidget extends ProxyWidget {const InheritedWidget({ Key key, Widget child }): super(key: key, child: child);@overrideInheritedElement createElement() => new InheritedElement(this);@protectedbool updateShouldNotify(covariant InheritedWidget oldWidget);
}1、InheritedWidget 的实现是对象池,所有InheritedWidget对象的实例都在这个对象池里,
可以在树的任何位置都拿到InheritedWidget的单例对象,所以可以做到在树中间传递消息。
2、对象池:在InheritedWidget中是一个数组Map<Type, InheritedElement> _inheritedWidgets;
3、InheritedWidget的作用域
InheritedWidget的作用域只能包括自己和自己的子节点 所以InheritedWidget的传递消息 只能往下传递。
4、一个封装了InheritedWidget的库

Provider (跨组件状态共享)

//定义一个保存共享数据的类
class InheritedProvider<T> extends InheritedWidget{InheritedProvider({@required this.data, Widget child}): super(child: child);// 共享状态使用泛型final T data;bool updateShouldNotify(InheritedProvider<T> old){// 返回true,则每次更新都会调用依赖其的子孙节点的didChangeDependenciesreturn true;}
}//数据发生变化时如何重构InheritedProvider
// 该方法用于Dart获取模板类型
Type _typeOf<T>() => T;class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget{ChangeNotifierProvider({Key key,this.data,this.child,});final Widget child;final T data;// 定义一个便捷方法,方便子树中的widget获取共享数据
//  static T of<T>(BuildContext context){
//    final type = _typeOf<InheritedProvider<T>>();
//    final provider = context.inheritFromWidgetOfExactType(type) as InheritedProvider<T>;
//    return provider.data;
//  }// 替换上面的便捷方法,按需求是否注册依赖关系static T of<T>(BuildContext context, {bool listen = true}){final type = _typeOf<InheritedProvider<T>>();final provider = listen? context.inheritFromWidgetOfExactType(type) as InheritedProvider<T>: context.ancestorInheritedElementForWidgetOfExactType(type)?.widget as InheritedProvider<T>;return provider.data;}_ChangeNotifierProviderState<T> createState() => _ChangeNotifierProviderState<T>();}

原理:

Model变化后会自动通知ChangeNotifierProvider(订阅者),ChangeNotifierProvider内部会重新构建InheritedWidget,而依赖该InheritedWidget的子孙Widget就会更新。
  可以发现使用Provider,将会带来如下收益:

业务代码更关注数据了,只要更新Model,则UI会自动更新,而不用在状态改变后再去手动调用setState()来显式更新页面。
数据改变的消息传递被屏蔽了,我们无需手动去处理状态改变事件的发布和订阅了,这一切都被封装在Provider中了。这真的很棒,帮我们省掉了大量的工作!
在大型复杂应用中,尤其是需要全局共享的状态非常多时,使用Provider将会大大简化我们的代码逻辑,降低出错的概率,提高开发效率。

Theme (颜色和主题)

factory ThemeData({// 深色还是浅色Brightness brightness,// 主题颜色样本MaterialColor primarySwatch,// 主色,决定导航栏颜色Color primaryColor,Brightness primaryColorBrightness,Color primaryColorLight,Color primaryColorDark,// 次级色,决定大多数Widget的颜色,如进度条、开关等Color accentColor,Brightness accentColorBrightness,Color canvasColor,Color scaffoldBackgroundColor,Color bottomAppBarColor,// 卡片颜色Color cardColor,// 分割线颜色Color dividerColor,Color focusColor,Color hoverColor,Color highlightColor,Color splashColor,InteractiveInkFeatureFactory splashFactory,Color selectedRowColor,Color unselectedWidgetColor,Color disabledColor,// 按钮颜色Color buttonColor,// 按钮主题ButtonThemeData buttonTheme,ToggleButtonsThemeData toggleButtonsTheme,Color secondaryHeaderColor,Color textSelectionColor,// 输入框光标颜色Color cursorColor,Color textSelectionHandleColor,Color backgroundColor,// 对话框背景颜色Color dialogBackgroundColor,Color indicatorColor,Color hintColor,Color errorColor,Color toggleableActiveColor,// 文字字体String fontFamily,// 字体主题,包括标题、body等文字样式TextTheme textTheme,TextTheme primaryTextTheme,TextTheme accentTextTheme,InputDecorationTheme inputDecorationTheme,// Icon的默认样式IconThemeData iconTheme,IconThemeData primaryIconTheme,IconThemeData accentIconTheme,SliderThemeData sliderTheme,TabBarTheme tabBarTheme,TooltipThemeData tooltipTheme,CardTheme cardTheme,ChipThemeData chipTheme,// 指定平台,应用特定平台控件风格TargetPlatform platform,MaterialTapTargetSize materialTapTargetSize,bool applyElevationOverlayColor,PageTransitionsTheme pageTransitionsTheme,AppBarTheme appBarTheme,BottomAppBarTheme bottomAppBarTheme,ColorScheme colorScheme,DialogTheme dialogTheme,FloatingActionButtonThemeData floatingActionButtonTheme,Typography typography,CupertinoThemeData cupertinoOverrideTheme,SnackBarThemeData snackBarTheme,BottomSheetThemeData bottomSheetTheme,PopupMenuThemeData popupMenuTheme,MaterialBannerThemeData bannerTheme,DividerThemeData dividerTheme,ButtonBarThemeData buttonBarTheme,})

OverflowBox 溢出父容器显示

//允许其子组件溢出OverflowBox的父组件显示
const OverflowBox({Key key,this.alignment = Alignment.center,this.minWidth, //对子组件的最小宽度约束this.maxWidth, //对子组件的最大宽度约束this.minHeight, //对子组件的最小高度约束this.maxHeight, //对子组件的最大高度约束Widget child,})注意:设置maxWidth或者maxHeight时,其值不能小于父组件的宽高,如果父组件有padding限制,则其值不能小于父组件的宽高减去Padding

FutureBuilder、StreamBuilder (异步UI更新)

FutureBuilder({// FutureBuilder依赖的Future,通常是一个异步耗时任务this.future,// 初始数据,用户设置默认数据this.initialData,// Widget构建器,该构建器会在Future执行的不同阶段被多次调用// 构建器签名为:Function(BuildContext context, AsyncSnapshot snapshot)// snapshot会包含当前异步任务的状态信息及结果信息,比如可以通过snapshot.connectionState获取异步任务的状态信息,通过snapshot.hasError判断任务时候有错误等@required this.builder,
})StreamBuilder({Key key,this.initialData,Stream<T> stream,@required this.builder,
})

对话框 Dialog

SimpleDialog

/*** 简单对话框,可以显示附加的提示和操作,通常配合SimpleDialogOption一起使用const SimpleDialog({Key key,this.title,//标题this.titlePadding = const EdgeInsets.fromLTRB(24.0, 24.0, 24.0, 0.0),//标题间距this.children,//要显示的内容this.contentPadding = const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0),//内容间距this.semanticLabel,//this.shape,//})*/

AlertDialog

/*** 提示对话框,显示提示内容和操作按钮* const AlertDialog({Key key,this.title,//标题this.titlePadding,//标题间距this.content,//要显示的内容项this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0),//内容间距this.actions,//底部按钮this.semanticLabel,//this.shape,//})*/

SnackBar

/**const SnackBar({Key key,@required this.content,//显示的内容this.backgroundColor,//设置背景颜色this.action,//可以添加事件this.duration = _kSnackBarDisplayDuration,this.animation,})*/

组合布局->

RelativeLayout (相对布局)

    return Stack(children: <Widget>[Container(width: 300,height: 300,color: Colors.red,),Text('这里是文本11',style: TextStyle(color: Colors.white),),Text('这里是文本22')],)child: Container(width: 300,height: 300,color: Colors.red,child: Stack(children: <Widget>[Align(alignment: Alignment.topCenter,child: Icon(Icons.account_circle,color: Colors.white,size: 40,),),Positioned(top: 50,left: 50,child:Icon(Icons.print,color: Colors.white,size: 40)),Icon(Icons.zoom_out_map,color: Colors.white,size: 40,),],),),);

应用组件->

MaterialApp

MaterialApp({Key key,this.title = '', // 设备用于为用户识别应用程序的单行描述this.home, // 应用程序默认路由的小部件,用来定义当前应用打开的时候,所显示的界面this.color, // 在操作系统界面中应用程序使用的主色。this.theme, // 应用程序小部件使用的颜色。this.routes = const <String, WidgetBuilder>{}, // 应用程序的顶级路由表this.navigatorKey, // 在构建导航器时使用的键。this.initialRoute, // 如果构建了导航器,则显示的第一个路由的名称this.onGenerateRoute, // 应用程序导航到指定路由时使用的路由生成器回调this.onUnknownRoute, // 当 onGenerateRoute 无法生成路由(initialRoute除外)时调用this.navigatorObservers = const <NavigatorObserver>[], // 为该应用程序创建的导航器的观察者列表this.builder, // 用于在导航器上面插入小部件,但在由WidgetsApp小部件创建的其他小部件下面插入小部件,或用于完全替换导航器this.onGenerateTitle, // 如果非空,则调用此回调函数来生成应用程序的标题字符串,否则使用标题。this.locale, // 此应用程序本地化小部件的初始区域设置基于此值。this.localizationsDelegates, // 这个应用程序本地化小部件的委托。this.localeListResolutionCallback, // 这个回调负责在应用程序启动时以及用户更改设备的区域设置时选择应用程序的区域设置。this.localeResolutionCallback, // this.supportedLocales = const <Locale>[Locale('en', 'US')], // 此应用程序已本地化的地区列表 this.debugShowMaterialGrid = false, // 打开绘制基线网格材质应用程序的网格纸覆盖this.showPerformanceOverlay = false, // 打开性能叠加this.checkerboardRasterCacheImages = false, // 打开栅格缓存图像的棋盘格this.checkerboardOffscreenLayers = false, // 打开渲染到屏幕外位图的图层的棋盘格this.showSemanticsDebugger = false, // 打开显示框架报告的可访问性信息的覆盖this.debugShowCheckedModeBanner = true, // 在选中模式下打开一个小的“DEBUG”横幅,表示应用程序处于选中模式
}) 

Scaffold

  const Scaffold({Key key,this.appBar,this.body,this.floatingActionButton,this.floatingActionButtonLocation,this.floatingActionButtonAnimator,this.persistentFooterButtons,this.drawer,this.endDrawer,this.bottomNavigationBar,this.bottomSheet,this.backgroundColor,this.resizeToAvoidBottomPadding,this.resizeToAvoidBottomInset,this.primary = true,this.drawerDragStartBehavior = DragStartBehavior.start,this.extendBody = false,this.drawerScrimColor,})appBar  AppBar  显示在界面顶部的一个AppBar
body    Widget  当前界面所显示的主要内容
floatingActionButton    Widget  在Material Design 中定义的一个功能
persistentFooterButtons List    固定在下方显示的按钮
drawer  Widget  侧边栏组件
bottomNavigationBar Widget  显示在底部的导航栏按钮
backgroundColor Color   当前界面所显示的主要内容
body    Widget  背景色
resizeToAvoidBottomPadding  bool    控制界面内容body是否重新布局来避免底部被覆盖,比如当键盘显示时,重新布局避免被键盘盖住内容。默认值为true

AppBar

AppBar({Key key,this.leading,this.automaticallyImplyLeading = true,this.title,this.actions,this.flexibleSpace,this.bottom,this.elevation,this.shape,this.backgroundColor,this.brightness,this.iconTheme,this.actionsIconTheme,this.textTheme,this.primary = true,this.centerTitle,this.titleSpacing = NavigationToolbar.kMiddleSpacing,this.toolbarOpacity = 1.0,this.bottomOpacity = 1.0,})leading 左侧显示的图标 通常首页显示的为应用logo 在其他页面为返回按钮
automaticallyImplyLeading 配合leading使用
title 标题文本
actions 右侧item
flexibleSpace 显示在 AppBar 下方的控件,高度和 AppBar 高度一样,可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用
bottom 一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏
elevation 控件的 z 坐标顺序,默认值 4,对于可滚动的 SliverAppBar,当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值。
shape
backgroundColor AppBar背景色
brightness AppBar亮度 有黑白两种主题
iconTheme AppBar上图标的样式
actionsIconTheme AppBar上actions图标的样式
textTheme AppBar上文本样式
centerTitle 标题是否居中
titleSpacing 标题与其他控件的空隙
toolbarOpacity AppBar tool区域透明度
bottomOpacity bottom区域透明度

BottomNavigationBar

/**BottomNavigationBar({Key key,@required this.items,//子选项this.onTap,this.currentIndex = 0,//选中第几个BottomNavigationBarType type,this.fixedColor,//文字颜色this.iconSize = 24.0,//icon图片大小})*//**const BottomNavigationBarItem({@required this.icon,//未选中图标this.title,//文字Widget activeIcon,//选中图标this.backgroundColor,// 测试发现type设置为shifting时,backgroundColor才有效})*/

TabBar

/**const TabBar({Key key,@required this.tabs,//显示的标签内容,一般使用Tab对象,也可以是其他的Widgetthis.controller,//TabController对象this.isScrollable = false,//是否可滚动this.indicatorColor,//指示器颜色this.indicatorWeight = 2.0,//指示器高度this.indicatorPadding = EdgeInsets.zero,//底部指示器的Paddingthis.indicator,//指示器decoration,例如边框等this.indicatorSize,//指示器大小计算方式,TabBarIndicatorSize.label跟文字等宽,TabBarIndicatorSize.tab跟每个tab等宽this.labelColor,//选中label颜色this.labelStyle,//选中label的Stylethis.labelPadding,//每个label的padding值this.unselectedLabelColor,//未选中label颜色this.unselectedLabelStyle,//未选中label的Style}) : assert(tabs != null),assert(isScrollable != null),assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)),assert(indicator != null || (indicatorPadding != null)),super(key: key);*/

Drawer

//UserAccountsDrawerHeader 可以设置用户头像、用户名、Email 等信息/**const UserAccountsDrawerHeader({Key key,this.decoration,//this.margin = const EdgeInsets.only(bottom: 8.0),//this.currentAccountPicture,//用来设置当前用户的头像this.otherAccountsPictures,//用来设置当前用户的其他账号的头像@required this.accountName,//当前用户的姓名@required this.accountEmail,//当前用户的邮箱this.onDetailsPressed//当 accountName 或者 accountEmail 被点击的时候所触发的回调函数,可以用来显示其他额外的信息})*///DrawerHeader自定义Drawer的头部信息
/**const DrawerHeader({Key key,this.decoration,//通常用来设置背景颜色或者背景图片this.margin = const EdgeInsets.only(bottom: 8.0),this.padding = const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 8.0),this.duration = const Duration(milliseconds: 250),this.curve = Curves.fastOutSlowIn,@required this.child,})*/

3,动画原理

原理:利用人眼会产生视觉暂留,是布局变化,简称:物理动画或帧动画

    //图片宽高从0变到300animation = new Tween(begin: 0.0, end: 300.0).animate(controller)..addListener(() {setState(()=>{});});//启动动画(正向执行)controller.forward();

hero动画:

A:  child: Hero(tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同child: ClipOval(child: Image.asset("images/avatar.png",width: 50.0,),),),B:  child: Hero(tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同child: Image.asset("images/avatar.png"),),

集合动画:

  final Animation<double> controller;Animation<double> height;Animation<EdgeInsets> padding;Animation<Color> color;Widget _buildAnimation(BuildContext context, Widget child) {return Container(alignment: Alignment.bottomCenter,padding:padding.value ,child: Container(color: color.value,width: 50.0,height: height.value,),);}@overrideWidget build(BuildContext context) {return AnimatedBuilder(builder: _buildAnimation,animation: controller,);}

4,调试与异常

调试:

Dart 分析器

运行flutter analyze测试你的代码。这个工具是一个静态代码检查工具,主要用于分析代码并帮助开发者发现可能的错误,比如,Dart分析器大量使用了代码中的类型注释来帮助追踪问题,避免var、无类型的参数、无类型的列表文字等。

Dart Observatory (语句级的单步调试和分析器)

debugger()、print、debugPrint、flutter logs

异常:

Dart中可以通过try/catch/finally来捕获代码块异常

@override
void performRebuild() {...try {//执行build方法  built = build();} catch (e, stack) {// 有异常时则弹出错误提示  built = ErrorWidget.builder(_debugReportException('building $this', e, stack));} ...
}

在发生异常时,Flutter默认的处理方式是弹一个ErrorWidget,上传异常如下:

FlutterErrorDetails _debugReportException(String context,dynamic exception,StackTrace stack, {InformationCollector informationCollector
}) {//构建错误详情对象  final FlutterErrorDetails details = FlutterErrorDetails(exception: exception,stack: stack,library: 'widgets library',context: context,informationCollector: informationCollector,);//报告错误 FlutterError.reportError(details);return details;
}

Dart中有一个runZoned(...) 方法,可以给执行对象指定一个Zone,它可以区域错误捕捉。

main() {runZoned(() => runApp(MyApp()), zoneSpecification: new ZoneSpecification(print: (Zone self, ZoneDelegate parent, Zone zone, String line) {parent.print(zone, "Intercepted: $line");}),);
}runZoned(() {runApp(MyApp());
}, onError: (Object obj, StackTrace stack) {var details=makeDetails(obj,stack);reportError(details);
});

5,包与插件(介绍插件使用,计划插件开发)

包与插件:功能集合的模块

alibaba/flutter_boost:路由
install_plugin 2.0.0#app下载更新插件
audio_recorder: any #录音、播放
flutter_sound: ^1.1.5#录音
dropdown_menu: ^1.1.0#下拉菜单
simple_permissions:#权限获取
easy_alert:#弹框
amap_location: any #高德地图
location: any #gogle位置获取
barcode_scan 0.0.8#二维码识别qr_mobile_vision: ^0.1.0 #二维码识别 这个不好用
flutter_screenutil: ^0.3.0#屏幕适配工具类
flutter_spinkit: ^2.1.0#加载等待框
lpinyin: ^1.0.6#汉字转拼音
shimmer: ^0.0.4#微光效果控件
qr_flutter: ^1.1.3#二维码生成
url_launcher: any#启动URL的Flutter插件。支持网络,电话,短信和电子邮件
datetime_picker_formfield: ^0.1.3#时间选择控件
flutter_picker: ‘^1.0.0’#选择器
common_utils: ‘^1.0.1’#工具类 时间、日期、日志等
flutter_html: ‘^0.8.2’#静态html标记呈现为Flutter小部件
fluwx: ‘^0.3.0’#微信支付、分享、登录
tobias: '^ 0.0.6#支付宝
cupertino_icons: ‘^0.1.2’#小图标控件
http: ‘^0.11.3+16’#网络请求
html: ‘^0.13.3’#html解析image_picker: ‘^0.4.5’#图片选择(相册或拍照)
flutter_webview_plugin: any#webview展示
fluttertoast: any#toast提示框
shared_preferences: ‘^0.4.2’#shared_preferences存储
transparent_image: ‘^0.1.0’#透明图片控件
flutter_swiper : ‘^1.0.2’#轮播图
charts_flutter: ‘^0.4.0’#统计图表
path_provider: ‘^0.4.1’#获取系统文件
cached_network_image: ‘0.4.1’#加载网络图片并本地缓存
sqflite: ‘^0.11.0+1’#sqllite数据库操作
pull_to_refresh: ‘^1.1.5’#下拉刷新上拉加载更多  //flutter_easyrefresh
video_player: ‘0.6.1’#视频播放
collection: ‘1.14.11’#集合操作工具类
device_info: ‘0.2.1’#获取手机信息
flutter_svg: ‘^0.3.2’#展示svg图标控件
intl: any#国际化工具类
connectivity: ‘0.3.1’#链接网络
flutter_staggered_grid_view:#瀑布流展示控件
flutter_file_manager:#文件管理
loader_search_bar:#导航栏搜索控件
flutter_image_compress : any#图片压缩
ota_update : any#App下载更新
flutter_slidable:#item侧滑控件
vercoder_inputer: ^0.8.0#验证码输入框
flutter_app_badger: ^1.0.2#桌面提示角标
flutter_badge: 0.0.1#控件显示角标
flutter_local_notifications: #设置通知栏消息提示
dragablegridview_flutter: ^0.1.9#可拖动删除的GridView
cool_ui: “^0.1.14”#自定义键盘

例如:

网络请求

自带HttpClient

try {//创建一个HttpClientHttpClient httpClient = new HttpClient();//打开Http连接HttpClientRequest request = await httpClient.getUrl(Uri.parse("https://www.baidu.com"));//使用iPhone的UArequest.headers.add("user-agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1");//等待连接服务器(会将请求信息发送给服务器)HttpClientResponse response = await request.close();//读取响应内容_text = await response.transform(utf8.decoder).join();//输出响应头print(response.headers);//关闭client后,通过该client发起的所有请求都会中止。httpClient.close();} catch (e) {_text = "请求失败:$e";} finally {setState(() {_loading = false;});}

第三方库Dio http库

    return new Container(alignment: Alignment.center,child: FutureBuilder(future: _dio.get("https://api.github.com/orgs/flutterchina/repos"),builder: (BuildContext context, AsyncSnapshot snapshot) {//请求完成if (snapshot.connectionState == ConnectionState.done) {Response response = snapshot.data;//发生错误if (snapshot.hasError) {return Text(snapshot.error.toString());}//请求成功,通过项目信息构建用于显示项目名称的ListViewreturn ListView(children: response.data.map<Widget>((e) =>ListTile(title: Text(e["full_name"]))).toList(),);}//请求未完成时弹出loadingreturn CircularProgressIndicator();}),);

路径插件

临时目录: 可以使用 getTemporaryDirectory() 来获取临时目录; 系统可随时清除的临时目录(缓存)。
在iOS上,这对应于NSTemporaryDirectory() 返回的值。
在Android上,这是getCacheDir())返回的值。
文档目录: 可以使用getApplicationDocumentsDirectory()来获取应用程序的文档目录,
该目录用于存储只有自己可以访问的文件。只有当应用程序被卸载时,系统才会清除该目录。
在iOS上,这对应于NSDocumentDirectory。
在Android上,这是AppData目录。
外部存储目录:可以使用getExternalStorageDirectory()来获取外部存储目录,
如SD卡;由于iOS不支持外部目录,所以在iOS下调用该方法会抛出UnsupportedError异常,
而在Android下结果是android SDK中getExternalStorageDirectory的返回值。

图片缓存以及清空

///实现Flutter框架的图像缓存的单例。
The singleton that implements the Flutter framework's image cache.///该缓存由ImageProvider内部使用,通常不应该直接访问。
The cache is used internally by [ImageProvider](https://docs.flutter.io/flutter/painting/ImageProvider-class.html) and should generally not be accessed directly.///图像缓存是在启动时由绘图绑定的绘图绑定创建的。createImageCache方法。
The image cache is created during startup by the  PaintingBinding's PaintingBinding.createImageCache  method.1.获取ImageCache 缓存对象ImageCache get imageCache => PaintingBinding.instance.imageCache;
2.设置缓存图片的个数(根据情况自己设置,default = 1000)imageCache.maximumSize = 1000;
3.获取缓存图片个数int num = imageCache.currentSize;
4.设置缓存大小(根据情况自己设置,default = 50M)imageCache.maximumSizeBytes=50<<20;
5.获取图片缓存大小(单位是byte,需自行转换到 M)
int byte=imageCache.currentSizeBytes
6.清除图片缓存imageCache.clear();

6,国际化

实现Localizations类

//Locale资源类
class DemoLocalizations {DemoLocalizations(this.isZh);//是否为中文bool isZh = false;//为了使用方便,我们定义一个静态方法static DemoLocalizations of(BuildContext context) {return Localizations.of<DemoLocalizations>(context, DemoLocalizations);}//Locale相关值,title为应用标题String get title {return isZh ? "Flutter应用" : "Flutter APP";}//... 其它的值
}

实现Delegate类

//Locale代理类
class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {const DemoLocalizationsDelegate();//是否支持某个Local@overridebool isSupported(Locale locale) => ['en', 'zh'].contains(locale.languageCode);// Flutter会调用此类加载相应的Locale资源类@overrideFuture<DemoLocalizations> load(Locale locale) {print("$locale");return SynchronousFuture<DemoLocalizations>(DemoLocalizations(locale.languageCode == "zh"));}@overridebool shouldReload(DemoLocalizationsDelegate old) => false;
}

添加多语言支持

localizationsDelegates: [// 本地化的代理类GlobalMaterialLocalizations.delegate,GlobalWidgetsLocalizations.delegate,// 注册我们的DelegateDemoLocalizationsDelegate()
],
接下来我们可以在Widget中使用Locale值:return Scaffold(appBar: AppBar(//使用Locale title  title: Text(DemoLocalizations.of(context).title),),... //省略无关代码)

使用插件 Intl包 可以轻松实现(忽略)

7,原理

事件(全局事件总线)

Flutter中可以使用Listener来监听原始触摸事件,按照本书对组件的分类,则Listener也是一个功能性组件。Listener({Key key,this.onPointerDown, //手指按下回调this.onPointerMove, //手指移动回调this.onPointerUp,//手指抬起回调this.onPointerCancel,//触摸事件取消回调this.behavior = HitTestBehavior.deferToChild, //在命中测试期间如何表现Widget child
})忽略PointerEvent
Listener(child: AbsorbPointer(child: Listener(child: Container(color: Colors.red,width: 200.0,height: 100.0,),onPointerDown: (event)=>print("in"),),),onPointerDown: (event)=>print("up"),
)

手势识别 (GestureDetector)

 return Center(child: GestureDetector(child: Container(alignment: Alignment.center,color: Colors.blue,width: 200.0, height: 100.0,child: Text(_operation,style: TextStyle(color: Colors.white),),),onTap: () => updateText("Tap"),//点击onDoubleTap: () => updateText("DoubleTap"), //双击onLongPress: () => updateText("LongPress"), //长按),);return Stack(children: <Widget>[Positioned(top: _top,left: _left,child: GestureDetector(child: CircleAvatar(child: Text("A")),//手指按下时会触发此回调onPanDown: (DragDownDetails e) {//打印手指按下的位置(相对于屏幕)print("用户手指按下:${e.globalPosition}");},//手指滑动时会触发此回调onPanUpdate: (DragUpdateDetails e) {//用户手指滑动时,更新偏移,重新构建setState(() {_left += e.delta.dx;_top += e.delta.dy;});},onPanEnd: (DragEndDetails e){//打印滑动结束时在x、y轴上的速度print(e.velocity);},),)],);

Dismissible ( 滑动删除 )

/***  滑动删除** const Dismissible({@required Key key,//@required this.child,//this.background,//滑动时组件下一层显示的内容,没有设置secondaryBackground时,从右往左或者从左往右滑动都显示该内容,设置了secondaryBackground后,从左往右滑动显示该内容,从右往左滑动显示secondaryBackground的内容//secondaryBackground不能单独设置,只能在已经设置了background后才能设置,从右往左滑动时显示this.secondaryBackground,//this.onResize,//组件大小改变时回调this.onDismissed,//组件消失后回调this.direction = DismissDirection.horizontal,//this.resizeDuration = const Duration(milliseconds: 300),//组件大小改变的时长this.dismissThresholds = const <DismissDirection, double>{},//this.movementDuration = const Duration(milliseconds: 200),//组件消失的时长this.crossAxisEndOffset = 0.0,//})*/

Flutter启动 ->

//启动过程分析 Flutter应用启动后要展示的第一个Widget
void runApp(Widget app) {WidgetsFlutterBinding.ensureInitialized()..attachRootWidget(app)..scheduleWarmUpFrame();
}
WidgetsFlutterBinding正是绑定widget 框架和Flutter engine的桥梁,定义如下:class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {static WidgetsBinding ensureInitialized() {if (WidgetsBinding.instance == null)WidgetsFlutterBinding();return WidgetsBinding.instance;}
}
Window正是Flutter Framework连接宿主操作系统的接口。我们看一下Window类的部分定义:
class Window {// 当前设备的DPI,即一个逻辑像素显示多少物理像素,数字越大,显示效果就越精细保真。// DPI是设备屏幕的固件属性,如Nexus 6的屏幕DPI为3.5 double get devicePixelRatio => _devicePixelRatio;// Flutter UI绘制区域的大小Size get physicalSize => _physicalSize;// 当前系统默认的语言LocaleLocale get locale;// 当前系统字体缩放比例。  double get textScaleFactor => _textScaleFactor;  // 当绘制区域大小改变回调VoidCallback get onMetricsChanged => _onMetricsChanged;  // Locale发生变化回调VoidCallback get onLocaleChanged => _onLocaleChanged;// 系统字体缩放变化回调VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;// 绘制前回调,一般会受显示器的垂直同步信号VSync驱动,当屏幕刷新时就会被调用FrameCallback get onBeginFrame => _onBeginFrame;// 绘制回调  VoidCallback get onDrawFrame => _onDrawFrame;// 点击或指针事件回调PointerDataPacketCallback get onPointerDataPacket => _onPointerDataPacket;// 调度Frame,该方法执行后,onBeginFrame和onDrawFrame将紧接着会在合适时机被调用,// 此方法会直接调用Flutter engine的Window_scheduleFrame方法void scheduleFrame() native 'Window_scheduleFrame';// 更新应用在GPU上的渲染,此方法会直接调用Flutter engine的Window_render方法void render(Scene scene) native 'Window_render';// 发送平台消息void sendPlatformMessage(String name,ByteData data,PlatformMessageResponseCallback callback) ;// 平台通道消息处理回调  PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;... //其它属性及回调}

本小结从应用代码层分析并理解,为后期温习以及生产项目打下基础。

Flutter 开源项目 上百案例集合下载

flutter 基础知识点总结相关推荐

  1. Flutter基础(三)Dart快速入门

    本文首发于公众号「刘望舒」 关联系列 ReactNative入门系列 React Native组件 Flutter基础系列 前言 Dart是Flutter SDK指定的语言,因此要学习Flutter, ...

  2. Python培训教程之Python基础知识点梳理

    Python语言是入门IT行业比较快速且简单的一门编程语言,学习Python语言不仅有着非常大的发展空间,还可以有一个非常好的工作,下面小编就来给大家分享一篇Python培训教程之Python基础知识 ...

  3. 自然语言处理算法工程师历史最全资料汇总-基础知识点、面试经验

    2019年秋招已过,零星的招聘任然在继续.本资源适用于NLP算法工程师面试,也适用于算法相关的其他岗位.整理了算法面试需要数学基础知识.编程语言.深度学习.机器学习.计算机理论.统计学习.自然语言处理 ...

  4. java重要基础知识点_必看 | 新人必看的Java基础知识点大梳理

    原标题:必看 | 新人必看的Java基础知识点大梳理 各位正在认真苦学Java的准大神,在这烈日炎炎的夏季里,老九君准备给大家带来一个超级大的"冰镇西瓜,"给大家清凉一下,压压惊. ...

  5. mysql 存储引擎 面试_搞定PHP面试 - MySQL基础知识点整理 - 存储引擎

    MySQL基础知识点整理 - 存储引擎 0. 查看 MySQL 支持的存储引擎 可以在 mysql 客户端中,使用 show engines; 命令可以查看MySQL支持的引擎: mysql> ...

  6. 布尔值_Python基础知识点手册——布尔值及布尔运算

    布尔值及布尔运算 布尔值有 True 和 False,布尔类型是整数类型的子类型,所以整数的运算都适用布尔值运算. issubclass(bool,int) True True + 1 2 ~True ...

  7. python基础知识整理-整理了27个新手必学的Python基础知识点

    原标题:整理了27个新手必学的Python基础知识点 1.执行脚本的两种方式 Python a.py 直接调用Python解释器执行文件 chomd +x a.py ./a.py #修改a.py文件的 ...

  8. python基础知识整理-python爬虫基础知识点整理

    首先爬虫是什么? 网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 根据我的经验,要学习Python爬虫 ...

  9. Python2.7基础知识点思维导图

    2019独角兽企业重金招聘Python工程师标准>>> 特别感谢廖雪峰官方网站! 这个思维导图是学习Python2.7时罗列的知识点,能够帮助快速回忆基础知识点,分享给各位. 思维导 ...

最新文章

  1. C++ vector的初始化、添加、遍历、插入、删除、查找、排序、释放操作
  2. spring学习记录(一)
  3. 首席Execution官
  4. nyromodal 非常棒的弹出层,可内嵌各种文件
  5. mysql表设计很多非常大的varchar_聊一聊数据库(MySQL)设计中的数据类型优化
  6. 【转】struct epoll_event
  7. 禁用vsftpd欢迎语
  8. 由深圳的大树所想到的
  9. 广东省深圳市谷歌卫星地图下载
  10. Axure RP 8汉化
  11. Node——request使用代理
  12. 15.4.1 使用CREATE OR REPLACE VIEW语句修改视图结构
  13. MySQL 高可用MMM安装部署以及故障转移详细资料汇总
  14. 京东广告推荐机器学习系统实践
  15. Python音乐下载
  16. bose蓝牙音箱使用说明_性价比甄选 推荐这5款超值得入手的蓝牙音箱
  17. Redis全部知识总结(概念、安装、用法、数据类型、事务、持久化、Jeids、订阅系统、缓存穿透及雪崩等)
  18. 女生被逼疯的日记(课余篇)
  19. 寻求真心话大冒险之猜数游戏的最佳策略
  20. JavaSE进阶318-331 构造方法习题

热门文章

  1. 《繁荣的真相》读书笔记
  2. 咱们玩家最幽默(关于《无极》)
  3. (五)AR Foundation实现图片检测(下)
  4. 电脑任务栏突然变得很宽很大
  5. VMware Workstation 中安装CentOS-7-x84_64-DVD-1708.iso
  6. apicloud传递数据
  7. 【领域泛化论文阅读】Birds of A Feather Flock Together:Category-Divergence Guidance for DomainAdaptiveSegmentat
  8. python test suite什么意思_如何:在python中设置testsuite
  9. 词汇导入词根词缀字典
  10. 笨笨图片批量抓取下载 V0.2 beta[C# | WinForm | 正则表达式 | HttpWebRequest | Async异步编程]...