在flutter中滥用statefulWidget将导致不可知的一些问题,其中一个问题就是会导致不停的rebuild整个页面,设想一下,你要是只需要点击一个按钮,更新一个按钮,却在点击这个按钮的时候,rebuild了整个页面,岂不是对性能的过大消耗?
为了解决这个问题,和直观的感觉这个问题,我引入了provider这个插件来作说明。
先上效果:
按第一个区域的按钮:
按下第二个区域后再按下第三个区域:
这里我用了三块区域来作说明:这三块区域都是使用的随机颜色,每次rebuild都会改变这些颜色。
首先,第一个区域是使用provider插件的,点击了按钮,counter会加1,但背景色没有做改变。
第二个区域使用的数据来自于最外面的statefulWidget,点击了按钮之后整个页面将会rebuild。
第三个区域是相当于一个叶子节点,它的counter数据来自于自己,点击按钮之后,这个区域会发生rebuild即只更新这个区域。
代码如下:
import 'dart:math';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'models/counter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CounterModel(0)),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Test()
)
);
}
}
class Test extends StatefulWidget {
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
// 这个counter将在第二区域中使用
int counter = 0;
_incrementCounter(){
setState(() {
++counter;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
constraints: BoxConstraints.expand(),
child: Column(
children: <Widget>[
Counter1(
title: '使用provider不会触发rebuild'
),
Counter2(
counter: counter,
onClick: _incrementCounter,
title: '使用的是最外层的数据,改变会触发整个页面的rebuild',
),
Counter3(
title: '叶子节点,使用的自己内部的数据,自身rebuild不会影响外面',
)
],
),
),
),
);
}
}
// 首先,第一个区域是使用provider插件的,点击了按钮,counter会加1,但背景色没有做改变
class Counter1 extends StatelessWidget {
final counter;
final title;
Counter1({this.counter,this.title});
BuildContext ctx;
@override
Widget build(BuildContext context) {
ctx = context;
Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
return Container(
child: Consumer(builder: (BuildContext context, CounterModel counterModel, Widget child){
return AnimatedContainer(
duration: Duration(seconds: 1),
color: color,
height: 150,
child: Column(
children: <Widget>[
Text(title,style: TextStyle(fontSize: 30)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('counter= ${counterModel.count}')
],
),
RaisedButton(
color: color,
textColor: Colors.white,
elevation: 20,
child: Text('点我增加'),
onPressed: _increment
)
],
),
);
})
);
}
void _increment() {
Provider.of<CounterModel>(ctx,listen: false).increment();
print(Provider.of<CounterModel>(ctx,listen: false).count);
}
}
// 第二个区域使用的数据来自于最外面的statefulWidget,点击了按钮之后整个页面将会rebuild。
class Counter2 extends StatelessWidget {
final VoidCallback onClick;
final int counter;
final String title;
Counter2({
Key key,
this.counter,
this.onClick,
this.title
});
@override
Widget build(BuildContext context) {
Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
return AnimatedContainer(
duration: Duration(milliseconds: 500),
color:color,
height: 250,
child:Column(
children: <Widget>[
Text(title,style: TextStyle(fontSize: 30),),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('counter = ${this.counter}',style: TextStyle(fontSize: 43,color: Colors.white),),
],
),
RaisedButton(
color: color,
textColor: Colors.white,
elevation: 20,
onPressed: onClick,
child: Text('increment Counter'),
),
],
),
);
}
}
// 第三个区域是相当于一个叶子节点,它的counter数据来自于自己,点击按钮之后,这个区域会发生rebuild即只更新这个区域。
class Counter3 extends StatefulWidget {
final title;
Counter3({
Key key,
this.title
}): super(key: key);
@override
_Counter3State createState() => _Counter3State();
}
class _Counter3State extends State<Counter3> {
int counter = 0;
@override
Widget build(BuildContext context) {
Color color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
return AnimatedContainer(
duration: Duration(milliseconds: 500),
color:color,
height: 250,
child:Column(
children: <Widget>[
Text(widget.title,style: TextStyle(fontSize: 30)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('counter = $counter',style: TextStyle(fontSize: 43,color: Colors.white),),
],
),
RaisedButton(
color: color,
textColor: Colors.white,
elevation: 20,
onPressed: _click,
child: Text('increment Counter'),
),
],
),
);
}
_click() {
setState(() {
++counter;
});
}
}
复制代码
第一个区域中的model文件:
import 'package:flutter/material.dart';
class CounterModel with ChangeNotifier {
int _count;
CounterModel(this._count);
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void setValue(int val) {
_count = val;
notifyListeners();
}
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END