目录
widget 的主要工作是通过实现 build 函数 来构建自身。一个 widget 通常由一些低级别的 widget 组成,flutter 框架依次的构建这些低级别的 widget,直到构建到最底层的子 widget 时,它会计算并描述 widget 的几何形状
flutter 中所有的对象都是一个 widget 。它既可以表示UI元素(如:Text / Image / Row / Column),也可表示功能性的组件(如:GestureDetectorWidget - 手势检测 / Theme - 数据传递)
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次")
],
);
}
}
flutter 提供了一套丰富、强大的基础 widget ,在此基础上还提供了Android 默认风格库: Material 与 IOS 风格库:Cupertino。
导入相应的依赖即可使用:
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
遵循 Material Design 规则。以 MaterialAppWidget 开始,包含有 Scaffold、AppBar、FlatButton 等。
使用前需要先引入依赖:
import 'package:flutter/material.dart';
Material 库中有一些 widget 可以根据实际运行平台切换风格,如 MaterialPageRoute,在路由切换时,切换动画会随平台不同而变化
遵循 IOS 应用风格,目前还没有 Material 库丰富。
使用前需要先引入依赖:
import 'package:flutter/cupertino.dart';
由于 Material 和 Cupertino 都是在基础 widget 库之上的,所以如果你的应用中引入了这两者之一,则不需要再引入 flutter/widgets.dart 了,因为它们内部已经引入过了。
widget 中主要包含了组件的配置数据,但它并不代表最终绘制在屏幕上的显示元素,真正代表屏幕上显示元素的是 element,widget 是 element 的配置数据,一个 widget 可同时对应多个 element
每一个 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 树的方法。
名称 | 返回值/类型 | 意义 |
---|---|---|
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
I/flutter (28866): 热重载 - reassemble
I/flutter (28866): State 移出 - deactivate
I/flutter (28866): State 删除 - dispose
管理状态的常见方法:
决定状态管理的原则:
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,
),
),
);
}
}