Widget简介
概念
Flutter中几乎所有的对象都是一个Widget,Flutter中的Widget的概念更广泛,它不仅可以表示UI元素,也可以表示一些功能性的组件如:用于手势检测的 GestureDetector
widget、用于APP主题数据传递的Theme
等等,
widget与Element
- Widget实际上就是
Element
的配置数据,Widget树实际上是一个配置树,而真正的UI渲染树是由Element
构成;不过,由于Element
是通过Widget生成的,所以它们之间有对应关系,在大多数场景,我们可以宽泛地认为Widget树就是指UI控件树或UI渲染树。 - 一个Widget对象可以对应多个
Element
对象。这很好理解,根据同一份配置(Widget),可以创建多个实例(Element)。
Widget主要窗口
@immutable
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key key;
@protected
Element createElement();
@override
String toStringShort() {
return key == null ? '$runtimeType' : '$runtimeType-$key';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
Widget
类继承自DiagnosticableTree
,DiagnosticableTree
即“诊断树”,主要作用是提供调试信息。Key
: 这个key
属性类似于React/Vue中的key
,主要的作用是决定是否在下一次build
时复用旧的widget,决定的条件在canUpdate()
方法中。createElement()
:正如前文所述“一个Widget可以对应多个Element
”;Flutter Framework在构建UI树时,会先调用此方法生成对应节点的Element
对象。此方法是Flutter Framework隐式调用的,在我们开发过程中基本不会调用到。debugFillProperties(...)
复写父类的方法,主要是设置诊断树的一些特性。canUpdate(...)
是一个静态方法,它主要用于在Widget树重新build
时复用旧的widget,其实具体来说,应该是:是否用新的Widget对象去更新旧UI树上所对应的Element
对象的配置;通过其源码我们可以看到,只要newWidget
与oldWidget
的runtimeType
和key
同时相等时就会用newWidget
去更新Element
对象的配置,否则就会创建新的Element
。
StatelessWidget
作用:用于不需要维护状态的场景,它通常在build
方法中通过嵌套其它Widget来构建UI,在构建过程中会递归的构建其嵌套的Widget。
继承自Widget
类,重写了createElement()
方法:
@override
StatelessElement createElement() => new StatelessElement(this);
Context
context是BuildContext
类的一个实例,表示当前widget在widget树中的上下文,每一个widget都会对应一个context对象(因为每一个widget都是widget树上的一个节点)。
StatefulWidget
StatefulWidget也是继承自Widget类,并重写了createElement()方法,不同的是返回的Element 对象并不相同;另外StatefulWidget类中添加了一个新的接口createState()
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => new StatefulElement(this);
@protected
State createState();
}
StatefulElement
间接继承自Element
类,与StatefulWidget相对应(作为其配置数据)。StatefulElement
中可能会多次调用createState()
来创建状态(State)对象。createState()
用于创建和Stateful widget相关的状态,它在Stateful widget的生命周期中可能会被多次调用。例如,当一个Stateful widget同时插入到widget树的多个位置时,Flutter framework就会调用该方法为每一个位置生成一个独立的State实例,其实,本质上就是一个StatefulElement
对应一个State实例。
state生命周期
import 'package:flutter/material.dart';
void main() => runApp(CounterWidget(
initValue: 10,
));
class CounterWidget extends StatefulWidget {
final int initValue;
const CounterWidget({Key key, this.initValue});
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter;
/**
* 第一次被调用
*/
@override
void initState() {
super.initState();
//初始化状态
_counter = widget.initValue;
print("生命周期:initState");
}
@override
Widget build(BuildContext context) {
print("生命周期:build");
return MaterialApp(
title: "计数器",
home: Scaffold(
appBar: AppBar(
title: Text("计数器"),
),
body: Center(
child: FlatButton(
child: Text("$_counter"),
//点击后计数器自增
onPressed: () => setState(() => ++_counter),
),
),
),
);
}
//在新旧widget的key和runtimeType同时相等时didUpdateWidget()就会被调用
@override
void didUpdateWidget(CounterWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print("生命周期:didUpdateWidget");
}
//state对象从树中被移除时调用
@override
void deactivate() {
super.deactivate();
print("生命周期:deactivate");
}
//state对象从树中被永久移除时调用
//通常用来回收和释放资源
@override
void dispose() {
super.dispose();
print("生命周期:dispose");
}
//只有热重载时候会调用
@override
void reassemble() {
super.reassemble();
print("生命周期:reassemble");
}
//依赖对象发生变化时被调用
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("生命周期:didChangeDependencies");
}
}
在Widget树中获取State对象,并调用SnackBar的两种方式
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "获取State对象",
home: Scaffold(
appBar: AppBar(
title: Text("获取State对象"),
),
body: GetState(),
),
);
}
}
class GetState extends StatefulWidget {
@override
_GetStateState createState() => _GetStateState();
}
class _GetStateState extends State<GetState> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
Builder(
builder: (context) {
return RaisedButton(
onPressed: () {
// 查找父级最近的Scaffold对应的ScaffoldState对象
ScaffoldState _scaffoldState =
context.ancestorStateOfType(TypeMatcher<ScaffoldState>());
//调用ScaffoldState的showSnackBar来弹出SnackBar
_scaffoldState.showSnackBar(
SnackBar(
content: Text("我是SnackBar"),
),
);
},
child: Text("点击显示SnackBar"),
);
},
),
Builder(
builder: (context) {
return RaisedButton(
onPressed: () {
// 直接通过of静态方法来获取ScaffoldState
ScaffoldState _scaffoldState =
Scaffold.of(context);
//调用ScaffoldState的showSnackBar来弹出SnackBar
_scaffoldState.showSnackBar(
SnackBar(
content: Text("我是SnackBar"),
),
);
},
child: Text("点击显示SnackBar"),
);
},
),
],
)
);
}
}
通过GlobalKey
来获取State
对象
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
//定义
static GlobalKey<ScaffoldState> _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "获取State对象",
home: Scaffold(
key: _globalKey, //设置key
appBar: AppBar(
title: Text("获取State对象"),
),
body: Center(
child: Column(
children: <Widget>[
Builder(
builder: (context) {
return RaisedButton(
onPressed: () {
// 查找父级最近的Scaffold对应的ScaffoldState对象
_globalKey.currentState.openDrawer();
},
child: Text("点击显示SnackBar"),
);
},
),
],
)),
),
);
}
}