目录
- Widget
- Element
- State
- 状态管理
Widget 的概念
widget 的主要工作是通过实现 build 函数 来构建自身。一个 widget 通常由一些低级别的 widget 组成,flutter 框架依次的构建这些低级别的 widget,直到构建到最底层的子 widget 时,它会计算并描述 widget 的几何形状
flutter 中所有的对象都是一个 widget 。它既可以表示UI元素(如:Text / Image / Row / Column),也可表示功能性的组件(如:GestureDetectorWidget - 手势检测 / Theme - 数据传递)
Widget 的分类
widget 可分为 无状态的 StatelessWidget 或者是有状态的 StatefulWidget,两者的区别在于状态的改变,需要根据当前widget是否需要管理一些状态来选择使用
StatelessWidget:无状态,比如标题栏中的标题
StatefulWidget:有状态,创建时需要指定一个 State ,在需要更新 UI时调用 setState(VoidCallbackfn),并在 VoidCallback 中改变一些些变量数值等,组件会重新 build 以达到数显状态/UI的效果。代码实例如下:
/**
* @des StatefulWidget 使用实例 - 计数器
* @author liyongli 20190409
* */
class Conunter extends StatefulWidget{
// 快捷写法
@override
_CounterState createState() => new _CounterState();
/**
* // 原始写法
* @override
* State<StatefulWidget> createState() {
* return new _CounterState();
* }
* */
}
/**
* 计数器操作模块
* */
class _CounterState extends State<Conunter>{
// 计数器
int number = 0;
// 按钮点击事件监听
void _numberAdd(){
setState(() {
number += 1;
});
}
@override
Widget build(BuildContext context) {
return new Row(
children: <Widget>[
new RaisedButton(
onPressed: _numberAdd,
child: new Text("ADD"),
),
new Text("更新数值: $number次")
],
);
}
}
Widget 支持库
flutter 提供了一套丰富、强大的基础 widget ,在此基础上还提供了Android 默认风格库: Material 与 IOS 风格库:Cupertino。
导入相应的依赖即可使用:
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
基础 Widget
- Text:文本
- Row:水平布局,基于 web Flexbox 布局模型。
- Column:垂直布局,基于 web Flexbox 布局模型。
- Stack:取代线性布局,与 Android 中 FrameLayout相似,允许子 widget 堆叠,使用 positioned 定位它们相对于上下左右四条边的位置。基于 web absolute positioning(绝对定位) 布局模型
- Container:矩形元素,可以装饰 BoxDecoration,如 background、边框、阴影,它可以具有边距(margins)、填充(padding)和应用与其大小的约束(constraints)。Container 可以使用矩阵在三维空间中对其进行变换
Material
遵循 Material Design 规则。以 MaterialAppWidget 开始,包含有 Scaffold、AppBar、FlatButton 等。
使用前需要先引入依赖:
import 'package:flutter/material.dart';
Material 库中有一些 widget 可以根据实际运行平台切换风格,如 MaterialPageRoute,在路由切换时,切换动画会随平台不同而变化
Cupertino
遵循 IOS 应用风格,目前还没有 Material 库丰富。
使用前需要先引入依赖:
import 'package:flutter/cupertino.dart';
由于 Material 和 Cupertino 都是在基础 widget 库之上的,所以如果你的应用中引入了这两者之一,则不需要再引入 flutter/widgets.dart 了,因为它们内部已经引入过了。
Element
widget 中主要包含了组件的配置数据,但它并不代表最终绘制在屏幕上的显示元素,真正代表屏幕上显示元素的是 element,widget 是 element 的配置数据,一个 widget 可同时对应多个 element
State 的概念
每一个 StatefulWidget 类都会对应一个 State 类,State 表示与其对应的 StatefulWidget 要维护的状态,保存的状态信息可以在 build 时被获取,同时,在 widget 生命周期中可以被改变,改变发生时,可以调用其 setState() 方法通知 framework 发生改变,framework 会重新调用 build 方法重构 widget 树,最终完成更新 UI 的目的。
state 中包含两个常用属性:widget 和 context。widget 属性表示当前正在关联的 widget 实例,但关联关系可能会在 widget 重构时发生变化(framework 会动态设置 widget 属性为最新的widget 对象)。context 属性是 buildContext 类的实例,表示构建 widget 的上下文,每个 widget 都有一个自己的 context 对象,它包含了查找、遍历当前 widget 树的方法。
State 的生命周期
- initState:当前 widget 对象插入 widget树中时调用
- didChangeDependencies:当前 State 对象的依赖项发生变化时调用
- build:绘制当前界面布局时调用
- reassemble:使用热重载时调用
- didUpdateWidget:widget 配置内容有变动重构时调用
- deactivate:当前 widget 对象从 widget 树中移出时调用
- dispose:当前 widget 对象从 widget 树中永久删除时调用
名称 | 返回值/类型 | 意义 |
---|---|---|
context read-only | BuildContext | The location in the tree where this widget builds. |
mounted read-only | bool | Whether this State object is currently in a tree. |
widget read-only | T | The current configuration. |
hashCode read-only, inherited | int | The hash code for this object. |
runtimeType read-only, inherited | Type | A representation of the runtime type of the object. |
build(BuildContext context) | Widget | 绘制当前界面布局时调用 / Describes the part of the user interface represented by this widget. |
deactivate() | void | 当前 widget 对象从 widget 树中移出时调用 / Called when this object is removed from the tree. |
debugFillProperties(DiagnosticPropertiesBuilder properties) | void | Add additional properties associated with the node. |
didChangeDependencies() | void | 当前 State 对象的依赖项发生变化时调用 / Called when a dependency of this State object changes. |
didUpdateWidget(T oldWidget) | void | widget 配置内容有变动重构时调用 / Called whenever the widget configuration changes. |
dispose() | void | 当前 widget 对象从 widget 树中永久删除时调用 / Called when this object is removed from the tree permanently. |
initState() | void | 当前 widget 对象插入 widget树中时调用 / Called when this object is inserted into the tree. |
reassemble() | void | 使用热重载时调用 / Called whenever the application is reassembled during debugging, for example during hot reload. |
setState (VoidCallback fn) | void | Notify the framework that the internal state of this object has changed. |
实际代码测试
/**
* @des StatefulWidget 使用实例 - 计数器
* @author liyongli 20190409
* */
class Conunter extends StatefulWidget{
// 快捷写法
@override
_CounterState createState() => new _CounterState();
/**
* // 原始写法
* @override
* State<StatefulWidget> createState() {
* return new _CounterState();
* }
* */
}
/**
* 计数器操作模块
* */
class _CounterState extends State<Conunter>{
// 计数器
int number = 0;
// 按钮点击事件监听
void _numberAdd(){
setState(() {
number += 1;
});
}
@override
Widget build(BuildContext context) {
print("widget 绘制 - build");
return new Row(
children: <Widget>[
new RaisedButton(
onPressed: _numberAdd,
child: new Text("ADD"),
),
new Text("更新数值: $number次")
],
);
}
@override
void initState() {
super.initState();
print("State 创建 - initState");
}
@override
void didUpdateWidget(Conunter oldWidget) {
super.didUpdateWidget(oldWidget);
print("widget 重构 - didUpdateWidget");
}
@override
void deactivate() {
super.deactivate();
print("State 移出 - deactivate");
}
@override
void dispose() {
super.dispose();
print("State 删除 - dispose");
}
@override
void reassemble() {
super.reassemble();
print("热重载 - reassemble");
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("State 更改 - didChangeDependencies");
}
}
- 首次运行时
I/flutter (28866): State 创建 - initState
I/flutter (28866): State 更改 - didChangeDependencies
I/flutter (28866): widget 绘制 - build
- 使用热重载时
I/flutter (28866): 热重载 - reassemble
I/flutter (28866): widget 重构 - didUpdateWidget
I/flutter (28866): widget 绘制 - build
- 更改路由(移除当前 widget)后使用热重载时
I/flutter (28866): 热重载 - reassemble
I/flutter (28866): State 移出 - deactivate
I/flutter (28866): State 删除 - dispose
StatefulWidget 状态管理
管理状态的常见方法:
- widget 管理自己的 state
- 父 widget 管理子 widget 状态
- 混合管理
决定状态管理的原则:
- 有关用户数据由父 widget 管理
- 有关界面效果由 widget 本身管理
- 状态被不同 widget 共享,由他们共同的父 widget 管理
widget 管理自己的 state
/**
* @des 管理自身状态
* @author liyongli 20190410
* */
class TapboxA extends StatefulWidget{
TapboxA({Key key}):super(key:key);
@override
_TapboxAState createState() => new _TapboxAState();
}
/**
* 颜色变化测试模块
* */
class _TapboxAState extends State<TapboxA>{
bool _active = false;
void _handleTap(){
setState(() {
_active = !_active;
});
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
_active ? "Activie" : "Inactive",
style: new TextStyle(fontSize: 32.0,color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: _active ? Colors.lightGreen[700] : Colors.grey[600]
),
),
),
);
}
}
父 widget 管理子 widget 状态
/**
* @des 父 widget 管理子 widget 状态
* @author liyongli 20190410
* */
class TapboxBParentWidget extends StatefulWidget {
@override
_TapboxBParentState createState() => new _TapboxBParentState();
}
/**
* 父 widget
* */
class _TapboxBParentState extends State<TapboxBParentWidget>{
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxB(
active: _active,
onChanged: _handleTapboxChanged
),
);
}
}
/**
* 子 widget
* */
class TapboxB extends StatelessWidget{
TapboxB({Key key, this.active: true, @required this.onChanged})
: super(key: key);
ValueChanged<bool> onChanged ;
bool active;
void _handleTap(){
onChanged(!active);
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
混合管理
/**
* @des 混合管理
* @author liyongli 20190410
* */
class ParentTapboxCWidget extends StatefulWidget{
@override
State<StatefulWidget> createState() => new ParentTapboxCState();
}
class ParentTapboxCState extends State<ParentTapboxCWidget>{
bool _active = false;
void _handleTapboxChanged(bool newValue){
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxCWidget(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
class TapboxCWidget extends StatefulWidget{
TapboxCWidget({Key key, this.active:false, @required this.onChanged}):super(key:key);
final bool active;
final ValueChanged<bool> onChanged;
@override
State<StatefulWidget> createState() => new TapboxCState();
}
class TapboxCState extends State<TapboxCWidget>{
bool _highlight = false;
void _handleTapDown(TapDownDetails details){
setState(() {
_highlight = true;
});
}
void _handleTapUp(TapUpDetails details){
setState(() {
_highlight = false;
});
}
void _handleCancel(){
setState(() {
_highlight = false;
});
}
void _handleTap(){
widget.onChanged(!widget.active);
}
@override
Widget build(BuildContext context) {
return new GestureDetector(
onTapDown: _handleTapDown,
onTapUp: _handleTapUp,
onTap: _handleTap,
onTapCancel: _handleCancel,
child: new Container(
child: new Center(
child: new Text(
widget.active ? "Active" : "Inactive",
style: new TextStyle(fontSize: :32.0,color: Colors.white),),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? new Border.all(
color: Colors.teal[700],
width: 10.0,
)
: null,
),
),
);
}
}
本篇到此完结,更多 Flutter 跨平台移动端开发 原创内容持续更新中~
期待您 关注 / 点赞 / 收藏 向着 大前端工程师 晋级!