Flutter01-核心基础-Widget 简介
Flutter01-核心基础-Widget 简介
Widget 简介
StatelessWidget
StatelessWidget 用于不需要维护状态的场景,它通常在build方法中通过嵌套其他 widget 来构建UI,在构建过程中会递归的构建其嵌套的 widget 。
下面的代码,实现了一个回显字符串的Echo
widget :
class Echo extends StatelessWidget {
const Echo({
Key? key,
required this.text,
this.backgroundColor = Colors.grey,
}) : super(key: key);
final String text;
final Color backgroundColor;
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: backgroundColor,
child: Text(
text,
textDirection: TextDirection.ltr,
),
),
);
}
}
void main(List<String> args) {
runApp(
const Echo(text: "hello"),
);
}
运行后效果如图:

Context
build 方法有一个context参数,它是BuildContext类的一个实例,表示当前 widget 在 widget 树中的上下文,每一个 widget 都会对应一个 context 对象,它提供了从当前 widget 开始向上遍历 widget 树以及按照 widget 类型查找父级 widget 的方法。
下面是在子树中获取父级 widget 的一个示例:
class ContextRoute extends StatelessWidget {
const ContextRoute({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>()!;
return (scaffold.appBar as AppBar).title!;
}
}
void main(List<String> args) {
runApp(MaterialApp(
title: "My App",
home: Scaffold(
appBar: AppBar(
title: const Text("Context 测试"),
),
body: const ContextRoute(),
),
));
}
运行后的效果如图:

StatefulWidget
-
createState() 用于创建和 StatefulWidget 相关的状态,它在StatefulWidget 的生命周期中可能会被多次调用。
-
例如,当一个 StatefulWidget 同时插入到 widget 树的多个位置时,Flutter 框架就会调用该方法为每一个位置生成一个独立的State实例
class CounterWidget extends StatefulWidget {
const CounterWidget({Key? key, this.initValue = 0});
final int initValue;
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
State
一个 StatefulWidget 类会对应一个 State 类,State表示与其对应的 StatefulWidget 要维护的状态,State 中的保存的状态信息可以:
-
在 widget 构建时可以被同步读取。
-
在 widget 生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter 框架状态发生改变,Flutter 框架在收到消息后,会重新调用其build方法重新构建 widget 树,从而达到更新UI的目的。
State 中有两个常用属性:
-
widget,它表示与该 State 实例关联的 widget 实例,由Flutter 框架动态设置。如果 widget 被修改了,Flutter 框架会动态设置State. widget 为新的 widget 实例。
-
context。StatefulWidget对应的 BuildContext,作用同StatelessWidget 的BuildContext。
State生命周期
实现一个计数器 CounterWidget 组件 ,点击它可以使计数器加1。
class CounterWidget extends StatefulWidget {
const CounterWidget({Key? key, this.initValue = 0}) : super(key: key);
final int initValue;
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
@override
void initState() {
super.initState();
//初始化状态
_counter = widget.initValue;
print("initState");
}
@override
Widget build(BuildContext context) {
print("build");
return MaterialApp(
title: "My App",
home: Scaffold(
body: Center(
child: TextButton(
child: Text('$_counter'),
//点击后计数器自增
onPressed: () => setState(
() => ++_counter,
),
),
),
),
);
}
@override
void didUpdateWidget(CounterWidget oldWidget) {
super.didUpdateWidget(oldWidget);
print("didUpdateWidget ");
}
@override
void deactivate() {
super.deactivate();
print("deactivate");
}
@override
void dispose() {
super.dispose();
print("dispose");
}
@override
void reassemble() {
super.reassemble();
print("reassemble");
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("didChangeDependencies");
}
}
void main(List<String> args) {
runApp(const CounterWidget());
}
StatefulWidget 生命周期如图:
在 widget 树中获取State对象
由于 StatefulWidget 的的具体逻辑都在其 State 中,所以很多时候,我们需要获取 StatefulWidget 对应的State 对象来调用一些方法,比如Scaffold组件对应的状态类ScaffoldState中就定义了打开 SnackBar(路由页底部提示条)的方法。
- 通过Context获取
context对象有一个findAncestorStateOfType()方法,该方法可以从当前节点沿着 widget 树向上查找指定类型的 StatefulWidget 对应的 State 对象。下面是实现打开 SnackBar 的示例:
class GetStateObjectRoute extends StatefulWidget {
const GetStateObjectRoute({Key? key}) : super(key: key);
@override
State<GetStateObjectRoute> createState() => _GetStateObjectRouteState();
}
class _GetStateObjectRouteState extends State<GetStateObjectRoute> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "My App",
home: Scaffold(
appBar: AppBar(
title: const Text("子树中获取State对象"),
),
body: Center(
child: Column(
children: [
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
// 查找父级最近的Scaffold对应的ScaffoldState对象
ScaffoldState _state =
context.findAncestorStateOfType<ScaffoldState>()!;
// 打开抽屉菜单
_state.openDrawer();
},
child: const Text('打开抽屉菜单1'),
);
}),
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
// 直接通过of静态方法来获取ScaffoldState
ScaffoldState _state = Scaffold.of(context);
// 打开抽屉菜单
_state.openDrawer();
},
child: const Text('打开抽屉菜单2'),
);
}),
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("我是SnackBar")),
);
},
child: const Text('显示SnackBar'),
);
}),
],
),
),
drawer: const Drawer(),
),
);
}
}
void main(List<String> args) {
runApp(const GetStateObjectRoute());
}
上面示例运行后,效果如图所示:

- 通过GlobalKey
class GetStateObjectRoute extends StatefulWidget {
const GetStateObjectRoute({Key? key}) : super(key: key);
@override
State<GetStateObjectRoute> createState() => _GetStateObjectRouteState();
}
class _GetStateObjectRouteState extends State<GetStateObjectRoute> {
// 定义一个globalKey, 由于GlobalKey要保持全局唯一性,我们使用静态变量存储
static final GlobalKey<ScaffoldState> _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "My App",
home: Scaffold(
key: _globalKey, // 设置key
appBar: AppBar(
title: const Text("子树中获取State对象"),
),
body: Center(
child: Column(
children: [
Builder(builder: (context) {
return ElevatedButton(
onPressed: () {
// 通过GlobalKey来获取State对象
(_globalKey.currentState as ScaffoldState).openDrawer();
},
child: const Text('打开抽屉菜单1'),
);
}),
],
),
),
drawer: const Drawer(),
),
);
}
}
void main(List<String> args) {
runApp(const GetStateObjectRoute());
}