Flutter 局部刷新/ 状态管理
在Flutter中,如果我们想要更新页面中的某个widget的状态的话,一般会使用setState方法重走build方法来刷新。
//Flutter是描述性的(declarative), UI反映状态.
UI = f(state)
当页面布局复杂的时候,这样肯定是不行的。 这边梳理了下几种常见的方式,做个记录,方便将来选型
总体分为两类:
第一类,Dart 和 Flutter 内置支持
Flutter里面最重要的方式 setState,规模较小的程序足够了,所有其它方式最终都需要调用 setState。
setState((){
_value = "new data";
});
2. Function callback, 主要的实现有: ChangeNotifier, ValueNotifier
ValueNotifier 里面包含一个 T value 值,当值改变的时候,会通知它的监听来刷新UI
ValueListenableBuilder需要的元素:
-
类型为 ValueWidgetBuilder<T> 的 builder, 监听对象的界面展现. 本质是一个方法,
Widget Function(BuildContext context, T value, Widget child)
-
ValueListenable<T> 对象 , 监听对象, 这里用它的实现类:
ValueNotifier
使用
//初始化
ValueNotifier<int> indexNotifier = ValueNotifier(0);
//数据变更:
indexNotifier.value = value;
//触发UI刷新
ValueListenableBuilder(
valueListenable: indexNotifier,
builder: (BuildContext context, int value, Widget child) {
return CircleCheckBox(
size: 40,
activeColor: Color(periwinkle),
value: _isSelect(value),
onChanged: _onSelect,
);
},
)
//销毁
indexNotifier.dispose();
ValueNofiter 其实跟Android DataBinding 里面的 ObserverField 类似,都是使用一个观察者模式来实现数据驱动UI修改。
使用过程发现,这个类有个bug 当Value 是List是使用,修改数据不会发出通知,需要手动调用 notifyLisener().
3. Global Key通信
GlobalKey能够跨Widget访问状态,相比于Flutter的 函数声明式编程 类似 android等其他平台的命令式调用
//初始化:
GlobalKey<SwitcherWidgetState> key = GlobalKey();
//使用:
key.currentState.changeState();
4. StreamBuilder
StreamBuilder也是官方内置的一种刷新UI方式。数据封装成 流 通知UI变更
//步骤1:初始化一个StreamController<可以是 int string... 一般是model>
final StreamController<String> _streamController = StreamController<String>();
//发送
_streamController.sink.add(_str);
//UI 变更
child: StreamBuilder<String>( // 监听Stream,每次值改变的时候,更新Text中的内容
stream: _streamController.stream,
initialData: _str,
builder: (BuildContext context, AsyncSnapshot<int> snapshot){
return Text('点击的时候这个值会改变: ${snapshot.data}');
}
),
// 销毁
_streamController.close();
5. FutureBuilder
通常用于是 异步编程,Future返回值是情况,它的构造方法:
const FutureBuilder({
Key key,
this.future, //获取数据的方法
this.initialData, //初始的默认数据
@required this.builder
}) : assert(builder != null),
super(key: key);
第二类,包-外部实现
1. provider
实现:
-
model类继承ChangeNotifer,
class CounterModel extends ChangeNotifier {
int value = 0;
void increment() {
value++;
notifyListeners();
}
void decrement() {
value--;
notifyListeners();
}
}
-
数据提供者: ChangeNotifierProvider
void main() => runApp(ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
));
-
数据消费者/操纵者, 有两种方式: Consumer包裹, 用Provider.of.
Consumer<CounterModel>(
builder: (context, counter, child) => Text(
'${counter.value}',
),
),
或者:
FloatingActionButton(
onPressed: () =>
Provider.of<CounterModel>(context, listen: false).increment(),
),
Provider性能相关的实现细节
-
Consumer包裹的范围要尽量小.
-
Consumer中builder方法的第三个参数child 可以用于缓存一些并不需要重建的widget:
return Consumer<CartModel>(
builder: (context, cart, child) => Stack(
children: [
// Use SomeExpensiveWidget here, without rebuilding every time.
child,
Text("Total price: ${cart.totalPrice}"),
],
),
// Build the expensive widget here.
child: SomeExpensiveWidget(),
);
- 点赞
- 收藏
- 关注作者
评论(0)