前言
最近基于想实现一个个人常用功能集合的APP了解到了跨平台方案。进而开始了对Flutter的学习,通过文章记录一下学习中的收获。
本篇文章的主要内容是对Flutter中状态管理的方式及不同方式的选择进行介绍。
本文首发于我的个人博客 技术公馆(wcc.im) : Flutter状态管理初探
目录
状态管理的方式
常见的状态管理方式有三种,分别是由Widget自身进行管理,由父Widget进行管理和由Widget自身及父Widget混合进行管理。
在对三种常见的状态管理方式进行分析时,我们定义了3个Tapbox,每个Tapbox可表示激活与未激活。这样Tapbox就是一个有状态的Widget。
由Widget自身进行管理
//------------------------- TapboxA ---------------------------------- 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(() { _active = !_active; }); } Widget build(BuildContext context) { return GestureDetector( onTap: _handleTap, child: Container( child: Center( child: Text( _active ? 'Active' : 'Inactive', 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自身进行状态管理非常简单,由TapboxA的状态类进行状态管理。使用 _active
来决定当前值与颜色并且使用 _handleTap
来改变其值。
由父Widget进行管理
//------------------------ ParentWidget -------------------------------- class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { bool _active = false; void _handleTapboxChanged(bool newValue) { setState(() { _active = newValue; }); } @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); final bool active; final ValueChanged<bool> onChanged; void _handleTap() { onChanged(!active); } Widget build(BuildContext context) { return GestureDetector( onTap: _handleTap, child: Container( child: Center( child: Text( active ? 'Active' : 'Inactive', 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进行管理主要有:
_active _handleTapboxChanged()
而子Widget主要的特点则是:
StatelessWidget
由Widget自身及父Widget混合进行管理
//---------------------------- ParentWidget ---------------------------- class ParentWidget extends StatefulWidget { @override _ParentWidgetState createState() => _ParentWidgetState(); } class _ParentWidgetState extends State<ParentWidget> { 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; _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); } Widget build(BuildContext context) { // This example adds a green border on tap down. // On tap up, the square changes to the opposite state. return GestureDetector( onTapDown: _handleTapDown, // Handle the tap events in the order that onTapUp: _handleTapUp, // they occur: down, up, tap, cancel 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, ), ), ); } }
可以看到这种模式只是将前两种模式进行结合。在示例中,通过 _highlight
增加了在Tapbox边缘增加边框的状态,该状态由Widget自身进行管理,而 _active
状态则由父Widget进行管理。
状态管理方式的选择
状态管理方式的选择总的来说通过以下方式:
- 如果所讨论的状态是用户数据,例如复选框的选中或未选中模式,或滑块的位置,则最好由父Widget来管理状态。
- 如果所讨论的状态是动画等状态,则最好由Widget本身来管理状态。