1.runApp函数接受一个给定的Widget并使其成为widget树的根
void main() => runApp(MyApp());
2.
无状态的widget: StatelessWidget
有状态的widget: StatefulWidget
3.build
widge的主要工作是实现一个build函数,用以构建自身
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Startup Name Generator', theme: new ThemeData( primaryColor: Colors.white ), home: new RandomWords(), ); } }
4.Material组件aterial应用程序以Material widget开始
Navigator管理由字符串标识的Widge栈(页面路由栈)
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Startup Name Generator', theme: new ThemeData( primaryColor: Colors.white ), home: new RandomWords(), ); } }
5.GestureDetector监听手势
6.位置类似于flex布局
crossAaisAlignment:子元素放置位置(十字轴)
mainAxisAlignment:子元素放置位置(主轴)
mainAxisSize:主轴占用多少空间
1.在Dart语言中使用下划线前缀表四符,会强制其变成私有的
2.i ~/ 2表示i除以2,但返回值是整型(向下取整)
1.Expanded:用于展开Row,Column或Flex的子项的窗口小部件
2.Scaffold:
appBar:水平栏,在程序的顶部
BottomAppBar:水平条,通常位于程序底部
3.appBar
actions:要在标题小部件后显示的小部件
4.Flutter之Offstage组件
/
**
* 控制child是否显示
*
当offstage为true,控件隐藏; 当offstage为false,显示;
当Offstage不可见的时候,如果child有动画等,需要手动停掉,Offstage并不会停掉动画等操作。
const Offstage({ Key key, this.offstage = true, Widget child })
*/
Navigator.of(context).push(new MaterialPageRoute(builder: (context) { //指定跳转的页面 return new Demo1(); },));
Wrap({ Key key, this.direction = Axis.horizontal, //排列方向,默认水平方向排列 this.alignment = WrapAlignment.start, //子控件在主轴上的对齐方式 this.spacing = 0.0, //主轴上子控件中间的间距 this.runAlignment = WrapAlignment.start, //子控件在交叉轴上的对齐方式 this.runSpacing = 0.0, //交叉轴上子控件之间的间距 this.crossAxisAlignment = WrapCrossAlignment.start, //交叉轴上子控件的对齐方式 this.textDirection, //textDirection水平方向上子控件的起始位置 this.verticalDirection = VerticalDirection.down, //垂直方向上子控件的其实位置 List<Widget> children = const <Widget>[], //要显示的子控件集合 })
SafeArea( child: Align( alignment: Alignment(-1, -1), child: Container( child: Text( "Hello", ), ), ), );
child: new Text( 'Hello, How are you?Hello, How are you?Hello, How are you?Hello, How are you?', textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, style: TextStyle(fontWeight: FontWeight.bold,fontSize: 48.0), maxLines: 2, ),
git checckout v0.8.1 切换到某个版本 flutter upgrade //同时更新Flutter SDK和你的依赖包
使用脚手架Scaffold可以设置AppBar,想要设置高度,在AppBar外包一层PreferredSize,设置preferredSize的属性为想要的高度即可
Scaffold( appBar: PreferredSize( child: AppBar( ), preferredSize: Size.fromHeight(screenSize.height * 0.07)) );
final size =MediaQuery.of(context).size; final width =size.width; final height =size.height;
注意:
MediaQuery.of(context) 要在WidgetsApp or MaterialApp 中,不然会报错 (在使用 MediaQuery.of(context)的地方并没有一个 WidgetsApp or MaterialApp 来提供数据)
例:
import 'package:flutter/material.dart'; class GetWidgetWidthAndHeiget extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final width = size.width; final height = size.height; print('width is $width; height is $height'); return Scaffold( appBar: AppBar( title: Text('Width & Height'), ), body: Center( child: Container( color: Colors.redAccent, width: width / 2, height: height / 2, ), ), ); } }
import 'package:flutter/material.dart'; void main() { runApp(new MaterialApp( title: "我的应用", home: new MyButton(), )); } class MyButton extends StatelessWidget { @override Widget build(BuildContext context) { //GestureDetector并不具有显示效果,而是检测由用户做出的手势(点击拖动和缩放) return new GestureDetector( //发生点击事件后回调 onTap: () { print("hia"); }, //发生双击时间后回调 onDoubleTap: (){ print("hia hia"); }, // 长按事件 onLongPress: (){ print("hia hia hia........"); }, child: new Container( height: 36.0, padding: const EdgeInsets.all(8.0), //上下左右都偏移8像素边距 margin: const EdgeInsets.symmetric(horizontal: 8.0), //symmetric的参数是可选的 水平方向 // 背景装饰 decoration: new BoxDecoration( //圆角和颜色 borderRadius: new BorderRadius.circular(5.0), color: Colors.lightGreen[500]), child: new Center(child: new Text("点击监听")), ), ); }
Color c = const Color(0xFF0099ff);//0x 后面开始 两位FF表示透明度16进制, Color c = const Colors.red[100]; Color c = const Color.fromARGB(0xFF, 0x42, 0xA5, 0xF5); Color c = const Color.fromARGB(255, 66, 165, 245); Color c = const Color.fromRGBO(66, 165, 245, 1.0);//opacity:不透明度
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, })
Slider 各部分的术语是:
- thumb - 用户拖动时水平滑动的形状。
- track - 滑块拇指滑过的线。
- value - 当用户拖动拇指指示所选值时弹出的形状。
- active - 滑块的“活动”一侧是拇指和最小值之间的一侧。
- inactive - 滑块的“非活动”侧是拇指和最大值之间的一侧。
Slider 有以下常用属性:
- activeColor → Color - 激活时的颜色。
- divisions → int - 离散部分的数量。
- inactiveColor → Color - 滑块轨道的非活动部分的颜色。
- label → String 滑块处于活动状态时显示在滑块上方的标签。
- max → double - 用户可以选择的最大值。
- min → double - 用户可以选择的最小值。
- onChanged → ValueChanged - 改变时触发。
- onChangeEnd → ValueChanged - 改变后触发。
- onChangeStart → ValueChanged - 改变前触发。
- value → double - 滑块的值。
Switch 有以下常用属性: activeColor → Color - 激活时原点的颜色。 activeThumbImage → ImageProvider - 原点还支持图片,激活时的效果。 activeTrackColor → Color - 激活时横条的颜色。 inactiveThumbColor → Color - 非激活时原点的颜色。 inactiveThumbImage → ImageProvider - 非激活原点的图片效果。 inactiveTrackColor → Color - 非激活时横条的颜色。 onChanged → ValueChanged - 改变时触发。 value → bool - 切换按钮的值。
value: 是否选中 是否打开 onChanged: 当打开关闭的时候的回调 activeColor: 选中时 滑块的颜色 activeTrackColor: 选中时 滑道的颜色 inactiveThumbColor: 未选中时 滑块的颜色 inactiveTrackColor: 未选中时 滑道的颜色 activeThumbImage: 选中时 滑块的图片 inactiveThumbImage: 未选中时 滑块的图片 title: 标题 典型的是 Text subtitle: 副标题 在标题下面的 典型的是 Text isThreeLine = false: 是不是三行, true 时: subtitle 不能为null, false时可以为 null dense: 是否垂直密集居中 secondary: 左边的一个东西 selected = false: 如果为 true ,则 text 和 icon 都用 activeColor 时的color
textAlign: TextAlign.center, //文本对齐方式 居中 textDirection: TextDirection.ltr, //文本方向 softWrap: false, //是否自动换行 false文字不考虑容器大小 单行显示 超出;屏幕部分将默认截断处理 overflow: TextOverflow .ellipsis, //文字超出屏幕之后的处理方式 TextOverflow.clip剪裁 TextOverflow.fade 渐隐 TextOverflow.ellipsis省略号 textScaleFactor: 2.0, //字体显示的赔率 maxLines: 10, //最大行数 style: new TextStyle( decorationColor: const Color(0xffffffff), //线的颜色 decoration: TextDecoration .none, //none无文字装饰 lineThrough删除线 overline文字上面显示线 underline文字下面显示线 decorationStyle: TextDecorationStyle .solid, //文字装饰的风格 dashed,dotted虚线(简短间隔大小区分) double三条线 solid两条线 wordSpacing: 0.0, //单词间隙(负值可以让单词更紧凑) letterSpacing: 0.0, //字母间隙(负值可以让字母更紧凑) fontStyle: FontStyle.italic, //文字样式,斜体和正常 fontSize: 20.0, //字体大小 fontWeight: FontWeight.w900, //字体粗细 粗体和正常 color: const Color(0xffffffff), //文字颜色
RaisedButton :凸起的按钮,其实就是Android中的Material Design风格的Button ,继承自MaterialButton
FlatButton :扁平化的按钮,继承自MaterialButton
OutlineButton :带边框的按钮,继承自MaterialButton
IconButton :图标按钮,继承自StatelessWidget
RaisedButton({ Key key, //点击按钮的回调出发事件 @required VoidCallback onPressed, //水波纹高亮变化回调 ValueChanged<bool> onHighlightChanged, //按钮的样式(文字颜色、按钮的最小大小,内边距以及shape)[ Used with [ButtonTheme] and [ButtonThemeData] to define a button's base //colors, and the defaults for the button's minimum size, internal padding,and shape.] ButtonTextTheme textTheme, //文字颜色 Color textColor, //按钮被禁用时的文字颜色 Color disabledTextColor, //按钮的颜色 Color color, //按钮被禁用时的颜色 Color disabledColor, //按钮的水波纹亮起的颜色 Color highlightColor, //水波纹的颜色 Color splashColor, //按钮主题高亮 Brightness colorBrightness, //按钮下面的阴影长度 double elevation, //按钮高亮时的下面的阴影长度 double highlightElevation, double disabledElevation, EdgeInsetsGeometry padding, ShapeBorder shape, Clip clipBehavior = Clip.none, MaterialTapTargetSize materialTapTargetSize, Duration animationDuration, Widget child, }
FloatingActionButton({ Key key, // 按钮上的组件,可以是Text、icon, etc. this.child, //长按提示 this.tooltip, // child的颜色(尽在child没有设置颜色时生效) this.foregroundColor, //背景色,也就是悬浮按键的颜色 this.backgroundColor, this.heroTag = const _DefaultHeroTag(), //阴影长度 this.elevation = 6.0, //高亮时阴影长度 this.highlightElevation = 12.0, //按下事件回调 @required this.onPressed, //是小图标还是大图标 this.mini = false, //按钮的形状(例如:矩形Border,圆形图标CircleBorder) this.shape = const CircleBorder(), this.clipBehavior = Clip.none, this.materialTapTargetSize, this.isExtended = false, })
PopupMenuButton({ Key key, //构建弹出式列表数据 PopupMenuItemBuilder<T> @required this.itemBuilder, //初始值 T initialValue, //选中时的回调 PopupMenuItemSelected<T> onSelected;, //当未选中任何条目后弹窗消失时的回调 final PopupMenuCanceled onCanceled;, // this.tooltip, //弹窗阴影高度 this.elevation = 8.0, //边距 this.padding = const EdgeInsets.all(8.0), //弹窗的位置显示的组件,默认为三个点... this.child, //跟child效果一致 this.icon, //弹窗偏移位置 this.offset = Offset.zero, })
Chip({ Key key, this.avatar,//标签左侧Widget,一般为小图标 @required this.label,//标签 this.labelStyle, this.labelPadding,//padding this.deleteIcon//删除图标, this.onDeleted//删除回调,为空时不显示删除图标, this.deleteIconColor//删除图标的颜色, this.deleteButtonTooltipMessage//删除按钮的tip文字, this.shape//形状, this.clipBehavior = Clip.none, this.backgroundColor//背景颜色, this.padding, this.materialTapTargetSize//删除图标material点击区域大小, })
cacheExtent → double - 视口在可见区域之前和之后有一个区域,用于缓存用户滚动时即将可见的项目。 controller → ScrollController - 一个可用于控制滚动视图滚动到的位置的对象。 physics → ScrollPhysics - 滚动视图应如何响应用户输入。 primary → bool - 是否是与父级关联的主滚动视图。 reverse → bool - 滚动视图是否在阅读方向上滚动。 scrollDirection → Axis - 滚动视图滚动的轴。 shrinkWrap → bool - 应该根据正在查看的内容确定滚动视图的范围。
其他知识:
EdgeInsets 这个类 通过他可以很好的控制widget上下左右的偏移量 有.all全部设置 也有.symmetric水平和垂直可选 也有.only上下左右可选
EdgeInsets.fromLTRB(10,10,10,10) ,L表示左边距(left缩写),T表示上边距(top缩写),R表示右边距(right缩写),B表示底边距(bottom缩写),四个值可以分开写;
它主要包含三方面的信息:
- 视图是完全由数据驱动。
- 视图产生的事件、回调,通过 Dispatch 发出“意图”,不做具体的实现。
- 需要用到的组件依赖等,通过 ViewService 标准化调用。 比如一个典型的符合 View 签名的函数。
Effect 是对非修改数据行为的标准定义,它是一个函数签名: (Context, Action) => Object,它主要包含四方面的信息:
- 接收来自 View 的“意图”,也包括对应的生命周期的回调,然后做出具体的执行。
- 它的处理可能是一个异步函数,数据可能在过程中被修改,所以我们不崇尚持有数据,而通过上下文来获取最新数据。
- 它不修改数据, 如果修要,应该发一个 Action 到 Reducer 里去处理。
- 它的返回值仅限于 bool or Future, 对应支持同步函数和协程的处理流程。 比如:良好的协程的支持。
它主要包含三方面的信息
- 接收一个“意图”, 做出数据修改。
- 如果要修改数据,需要创建一份新的拷贝,修改在拷贝上。
- 如果数据修改了,它会自动触发 State 的层层数据的拷贝,再以扁平化方式通知组件刷新。
Adapter 也是对局部的展示和功能的封装。它为 ListView 高性能场景而生,它是 Component 实现上的一种变化。
1.它的目标是解决 Component 模型在 flutter-ListView 的场景下的 3 个问题:
- 将一个"Big-Cell"放在 Component 里,无法享受 ListView 代码的性能优化。
- Component 无法区分 appear|disappear 和 init|dispose 。
- Effect 的生命周期和 View 的耦合,在 ListView 的场景下不符合直观的预期。 概括的讲,我们想要一个逻辑上的 ScrollView,性能上的 ListView ,这样的一种局部展示和功能封装的抽象。 做出这样独立一层的抽象是, 我们看实际的效果, 我们对页面不使用框架,使用框架 Component,使用框架 Component+Adapter 的性能基线对比。
2.Reducer is long-lived, Effect is medium-lived, View is short-lived. 我们通过不断的测试做对比,以某 android 机为例。
3.使用框架前 我们的详情页面的 FPS,基线在 52FPS。
4.使用框架, 仅使用 Component 抽象下,FPS 下降到 40, 遭遇“Big-Cell”的陷阱。
5.使用框架,同时使用 Adapter 抽象后,FPS 提升到 53,回到基线以上,有小幅度的提升。
static Action didLoadAction(Home home) { return Action(HomePageAction.didLoad, payload: home); } void _init(Action action, Context<HomePageState> ctx) async { APIs.getHome().then((home) { ctx.dispatch(HomePageActionCreator.didLoadAction(home)); }); } onSelect(Action action, Context ctx) async { String videoId = action.payload["videoId"]; VideoDetail videoDetail = await APIs.getVideo(videoId); Map<String, dynamic> payload = { "videoId": videoId, "videoDetail": videoDetail }; Navigator.of(ctx.context).push(MaterialPageRoute(builder: (context) { return VideoPage().buildPage(payload); })); }
13.颜色透明度
带有accent的颜色每个有4中颜色,如 Colors.redAccent,Colors.redAccent[100], Colors.redAccent[200], Colors.redAccent[400], Colors.redAccent[700], Color.fromARGB(100, 10, 100, 100),A表示不透明度,值从0-255,RGB值也是从0-255; Color.fromRGBO(100, 10, 10, 1),O表示不透明度,值从0-1,RGB值是从0-255; Color.alphaBlend(Color.fromRGBO(10, 10, 255, 0.1), Color.fromRGBO(100, 10, 255, 0.5)) ,这个是颜色的混合, 颜色会根据不透明度进行合并; 如果前者的不透明度为1,就只显示前者颜色,前者为0,颜色为后者,否则就是按照前后者的不透明度和颜色进行混合
tools:replace="android:label" xmlns:tools="http://schemas.android.com/tools" tools:replace="android:label,android:allowBackup" buildToolsVersion '28.0.2' tools:replace="android:label,android:allowBackup,android:appComponentFactory" xmlns:tools="http://schemas.android.com/tools" implementation 'androidx.appcompat:appcompat:1.0.0-alpha1' implementation 'androidx.constraintlayout:constraintlayout:1.1.2'
(1)initState
当插入渲染树的时候调用,这个函数在生命周期中只调用一次。这里可以做一些初始化工作,比如初始化State的变量。
(2)didChangeDependencies
使用场景
new DefaultTabController(length: 3, child: new TabBar( tabs: [ "主页","订单","我的" ] .map( (data)=>new Text(data) ).toList(),
(3)didUpdateWidget
当组件的状态改变的时候就会调用didUpdateWidget,比如调用了setState.实际上这里flutter框架会创建一个新的Widget,绑定本State,并在这个函数中传递老的Widget。这个函数一般用于比较新、老Widget,看看哪些属性改变了,并对State做一些调整。
(4)deactivate
当State对象从树中被移除时,会调用此回调
(5)dispose
一旦到这个阶段,组件就要被销毁了,这个函数一般会移除监听,清理环境。
例子:
假设我们从A页面跳转到B页面, 那么A,B页面的生命周期会是怎样的呢? B页面进入初始化状态,依次执行4个函数:构造函数 > initState > didChangeDependencies > Widget build , 此时页面加载完成,进入运行态。 此时A页面依次执行deactivate > build函数。注意 此时A页面并未卸载。 然后我们假设B页面只有一个按钮,点击B页面中的按钮,改变按钮的文字,会执行widget的build方法 ,(理论上也应该执行didUpdateWidget,但我这里没有)。 这时,我们点击返回键从B页面返回到A页面。 A页面重新显示,B页面开始卸载。 那么A先执行deactivate > build , 然后B页面依次执行:deactivate > dispose 。 此时A页面进入运行态,B页面移除