一、为什么要使用局部刷新
Flutter中有两个常用的状态Widget分为StatefulWidget和StatelessWidget,分别为动态视图和静态视图,视图的更新需要调用StatefulWidget的setState方法,这会遍历调用子Widget的build方法。如果一个页面内容比较复杂时,会包含多个widget,如果直接调用setState,会遍历所有子Widget的build,这样会造成很多不必要的开销,有时候界面和数据比较复杂的时候,会出现未知的错误。所以,为了保证代码的性能和健壮性,我们最好使用局部刷新的方式。
二、StatefulBuilder
使用的核心代码:
class DemoStatefulBuilderPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
//状态构建器
body: buildStatefulBuilder(),
);
}
}
int _count = 0;
StatefulBuilder buildStatefulBuilder() {
return StatefulBuilder(
//构建状态改变的Widget
builder: (BuildContext context, void Function(void Function()) setState) {
//居中
return Center(
//手势识别
child: GestureDetector(
child: Text("早起的年轻人 $_count"),
//单击事件
onTap: () {
//刷新当前 StatefulBuilder 中的状态
setState(() {
_count++;
});
},
),
);
},
);
}

三、通过GlobalKey局部刷新
globalkey唯一定义了某个element,它使你能够访问与element相关联的其他对象,例如buildContext、state等。
使用场景:可以通过key.currentState拿到它的状态对象,然后就可以调用其中的onPressed方法。
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
GlobalKey<_TextWidgetState> textKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
TextWidget(textKey),// 需要更新的Text
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
_counter ++;// 这里我们只给他值变动,状态刷新交给下面的key事件
textKey.currentState.onPressed(_counter);//这个counter的值已经改变了,但是没有重绘所以我们看到的知识我们定义的初始值
},
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
方法的调用:
class TextWidget extends StatefulWidget {
final Key key;
const TextWidget(this.key);
@override
_TextWidgetState createState() => _TextWidgetState();
}
class _TextWidgetState extends State<TextWidget> {
String _text = "0";
@override
Widget build(BuildContext context) {
return Center(child: Text(_text, style: TextStyle(fontSize: 20),),);
}
void onPressed(int count) {
setState(() {
_text = count.toString();
});
}
}
四、FutureBuilder & StreamBuilder
使用场景:异步UI更新
很多时候我们会依赖一些异步数据来动态更新UI,比如在打开一个页面时我们需要先从互联网上获取数据,在获取数据的过程中显示一个加载框,等获取到数据时我们再渲染页面;又比如我们想展示Stream(比如文件流、互联网数据接收流)的进度。当然StatefulWidget我们完全可以实现以上功能。但由于在实际开发中依赖异步数据更新UI的这种场景非常常见,并且当StatefulWidget中控件树较大时,更新一个属性导致整个树重建,消耗性能,因此Flutter专门提供了FutureBuilder和SteamBuilder两个组件来快速实现这种功能。
1、FutureBuilder的使用
class _MyHomePageState extends State<MyHomePage> {
Future<String> mockNetworkData() async {
return Future.delayed(Duration(seconds: 2), () => "我是从互联网上获取的数据");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
FutureBuilder(
future: mockNetworkData(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if(snapshot.connectionState == ConnectionState.done){
if(snapshot.hasError){
// 请求失败,显示错误
return Text("Error: ${snapshot.error}");
}else {
// 请求成功,显示数据
return Text("Contents: ${snapshot.data}");
}
}else {
return CircularProgressIndicator();
}
}),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
2、SteamBuilder的使用
class _MyHomePageState extends State<MyHomePage> {
Stream<int> counter(){
return Stream.periodic(Duration(seconds: 1), (i){
return i;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
StreamBuilder(
stream: counter(),
builder: (BuildContext context, AsyncSnapshot<int> snapshot){
if(snapshot.hasError){
return Text("Error: ${snapshot.error}");
}
switch (snapshot.connectionState){
case ConnectionState.none:
return Text("没有Stream");
case ConnectionState.waiting:
return Text("等待数据、、、");
case ConnectionState.active:
return Text("active: ${snapshot.data}");
case ConnectionState.done:
return Text("Stream已关闭");
}
return null;
}),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
网友评论