动画
AnimatedSwitcher 小部件(包含在 SDK 中,与 Provider 无关)可能足以在显示连接/断开状态的两个小部件之间进行动画处理。 (如果您只是在 Container 的构造函数参数列表中切换颜色或其他内容,AnimatedContainer 也可以工作。)
AnimatedSwitcher 的孩子需要 key,当孩子属于同一班级但内部不同时。如果它们是完全不同的 Type,Flutter 知道在两者之间进行动画处理,但如果它们是相同的 Type,则不会。 (与 Flutter 如何分析小部件树以寻找所需的重建有关。)
仅重建受影响的小部件
在下面的示例中,YellowWidget 没有被重建,它的父级也没有。在示例中从已连接状态更改为已断开连接状态时,仅重建 Consumer<InternetStatus> 小部件。
我不是 Provider 方面的专家,我发现在知道使用哪个 Provider/Consumer/Selector/watcher 以避免不必要的重建时很容易出错。如果 Provider 没有为您点击,您可能对 Get 或 RxDart+GetIt 等其他状态管理解决方案感兴趣。
注意:额外的 Builder 小部件用作 ChangeNotifierProvider 子级的父级,以使所有内容都位于子级之下。这允许 InheritedWidget 按预期运行(构建 Provider 的基础)。否则,ChangeNotifierProvider 的子节点实际上将共享其上下文并成为其兄弟,而不是后代。
即他们都会得到这里显示的上下文:
class ProviderGranularPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
这也是 Flutter 的一个微妙之处。如果你wrap your entire MaterialApp or MyApp widget in Provider,这个额外的Builder显然是没有必要的。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class InternetStatus extends ChangeNotifier {
bool connected = true;
void setConnect(bool _connected) {
connected = _connected;
notifyListeners();
}
}
/// Granular rebuilds using Provider package
class ProviderGranularPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<InternetStatus>(
create: (_) => InternetStatus(),
child: Builder(
builder: (context) {
print('Page (re)built');
return SafeArea(
child: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 3,
child: Consumer<InternetStatus>(
builder: (context, inetStatus, notUsed) {
print('status (re)built');
return AnimatedSwitcher(
duration: Duration(seconds: 1),
child: Container(
key: getStatusKey(context),
alignment: Alignment.center,
color: getStatusColor(inetStatus),
child: getStatusText(inetStatus.connected)
),
);
},
),
),
Expanded(
flex: 3,
child: YellowWidget(),
),
Expanded(
flex: 1,
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RaisedButton(
child: Text('Connect'),
onPressed: () => setConnected(context, true),
),
RaisedButton(
child: Text('Disconnect'),
onPressed: () => setConnected(context, false),
)
],
),
),
)
],
),
),
);
},
),
);
}
/// Show other ways to access Provider State, using context & Provider.of
Key getStatusKey(BuildContext context) {
return ValueKey(context.watch<InternetStatus>().connected);
}
void setConnected(BuildContext context, bool connected) {
Provider.of<InternetStatus>(context, listen: false).setConnect(connected);
}
Color getStatusColor(InternetStatus status) {
return status.connected ? Colors.blue : Colors.red;
}
Widget getStatusText(bool connected) {
String _text = connected ? 'Connected' : 'Disconnected';
return Text(_text, style: TextStyle(fontSize: 25));
}
}
class YellowWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Yellow was (re)built');
return Container(
color: Colors.yellow,
child: Center(
child: Text('This should not rebuild'),
),
);
}
}