开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
1、Widget 管理方式有哪几种
- Widget 自己管理。通常是不会和其他界面产生联动的Widget,比如Widget自身的背景色、动画等。。
- Widget 父Widget 管理。在进行组件封装时常会这样,将一些属性开放出去交给父Widget控制,便于复用和灵活管理。
- 混合管理 也就是父Widget和子Widget 都管理状态。 下面看源码例子:
1.1、Widget管理自身的状态
class TapboxA extends StatefulWidget {
TapboxA({Key? key}) : super(key: key);
@override
_TapboxAState createState() => _TapboxAState();
}
class _TapboxAState extends State<TapboxA> {
bool _active = false;//颜色高亮控制
void _handleTap() {//点击事件
setState(() {
改变State状态,刷新UI界面
_active = !_active;
});
}
Widget build(BuildContext context) {
return GestureDetector(//添加手势
onTap: _handleTap,//手势响应事件
child: Container(//事件管理的子Widget、Container:容器组件
child: Center(
child: Text(//文本控件
_active ? 'Active' : 'Inactive',//根据_active显示文字内容
style: TextStyle(fontSize: 32.0, color: Colors.white),//文字风格
),
),
width: 200.0,//Container 组件宽高
height: 200.0,
decoration: BoxDecoration(//Container组件装饰器,用来添加一些特殊效果、比如阴影、特效等
color: _active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
- 点击GestureDetector 包裹的子控件,事件响应_handleTap
- 事件响应改变数据_active状态
- 调用setState函数通知Flutter刷新UI 可以看到,整个UI的改变都是在_TapboxAState内部进行的,也就是State的状态都是自身在管理。
1.2、父Widget管理子Widget状态
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;//父Widget创建管理状态数据
void _handleTapboxChanged(bool newValue) {//事件响应
setState(() {
_active = newValue;//赋值、改变状态,通知刷新UI
});
}
@override
Widget build(BuildContext context) {
return Container(
child: TapboxB(
active: _active,//状态传递
onChanged: _handleTapboxChanged,//事件传递,
),
);
}
}
//------------------------- TapboxB ----------------------------------
class TapboxB extends StatelessWidget {
TapboxB({Key? key, this.active: false, required this.onChanged})
: super(key: key);//构造函数 required 为必须参数 active 默认为false,如果有传递值则会赋值为传递值。
final bool active;
final ValueChanged<bool> onChanged;//一个函数属性,类似于iOS中的block
void _handleTap() {
onChanged(!active);//事件回调
}
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,//事件传递到_handleTap
child: Container(
child: Center(
child: Text(
active ? 'Active' : 'Inactive',//根据active状态显示文本值
style: TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
- 父Widget 创建接收事件响应函数_handleTapboxChanged以及active。
- 构建子Widget 将active和_handleTapboxChanged传递进子Widget
- 子widget通过传递的active显示内容
- 子widget通过点击事件_handleTap将事件传递回父函数_handleTapboxChanged处理
- 父widget通过修改active状态,通知UI刷新,重新构建UI,完成界面刷新。 可以看到,父Widget负责状态事件处理,然后将状态数据传递给子Widget,子Widget则负责界面展示,不负责状态管理。
1.3、混合状态管理
class ParentWidgetC extends StatefulWidget {
@override
_ParentWidgetCState createState() => _ParentWidgetCState();
}
class _ParentWidgetCState extends State<ParentWidgetC> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return Container(
child: TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//----------------------------- TapboxC ------------------------------
class TapboxC extends StatefulWidget {
TapboxC({Key? key, this.active: false, required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
@override
_TapboxCState createState() => _TapboxCState();
}
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
void _handleTap() {
widget.onChanged(!widget.active);
}
@override
Widget build(BuildContext context) {
// 在按下时添加绿色边框,当抬起时,取消高亮
return GestureDetector(
onTapDown: _handleTapDown, // 处理按下事件
onTapUp: _handleTapUp, // 处理抬起事件
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: Container(
child: Center(
child: Text(
widget.active ? 'Active' : 'Inactive',
style: TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? Border.all(
color: Colors.teal[700],
width: 10.0,
)
: null,
),
),
);
}
}
- 两种状态分开管理,子Widget管理自身的高亮状态,通过_highlight属性
- 父Widget 通过active 管理子widget的内容显示和颜色。
2、页面之前传递数据
上面的例子可以看到页面之间数据的传递方式
class TapboxC extends StatefulWidget {
TapboxC({Key? key, this.active: false, required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
@override
_TapboxCState createState() => _TapboxCState();
}
- 在需要传递的Widget上创建对应的属性,然后在构造函数上带上需要接收的参数
- required 带上这个关键字则为必须参数
- Key? 带上?则为可为空参数