管理状态的最常见的方法:
方法 | 描述 |
---|---|
自身状态管理 | Widget管理自己的状态。 |
父组件管理子组件状态 | 父Widget管理子Widget状态。 |
混合管理 | 混合管理(父Widget和子Widget都管理状态)。 |
全局状态管理 | 使用第三方库进行全局状态管理 |
关于状态管理原则:
- 如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父Widget管理。
- 如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由Widget本身来管理。
- 如果某一个状态是不同Widget共享的则最好由它们共同的父Widget管理。
在Widget内部管理状态封装性会好一些,而在父Widget中管理会比较灵活。有些时候,如果不确定到底该怎么管理状态,那么推荐的首选是在父widget中管理(灵活会显得更重要一些)。
一. 组件自身管理自身状态
自己管理自己的状态比较简单, 参数在组件内部 , 同时 setState也在自己内部
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("组件自己管理自己状态"),
),
body: SelfWidget(),
);
}
}
class SelfWidget extends StatefulWidget {
@override
_SelfWidgetState createState() => _SelfWidgetState();
}
class _SelfWidgetState extends State<SelfWidget> {
bool _isActive = false;
_handleTap() {
setState(() {
_isActive = !_isActive;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: Container(
width: 200,
height: 200,
color: _isActive ? Colors.amber : Colors.blueAccent,
),
);
}
}
二. 父组件管理子组件
父组件将参数和方法传给子组件供子组件调用, 子组件调用方法其实是在父组件中setState了.
子组件可以是无状态组件, 因为它并没有管理自身状态
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("父组件管理子组件状态"),
),
body: ParentsWidget(),
);
}
}
class ParentsWidget extends StatefulWidget {
@override
_ParentsWidgetState createState() => _ParentsWidgetState();
}
class _ParentsWidgetState extends State<ParentsWidget> {
bool _isActive = false;
void _tapToChangeColor(v) {
setState(() {
_isActive = v;
});
}
@override
Widget build(BuildContext context) {
return SonWidget(isActive: _isActive, tapFunction: _tapToChangeColor);
}
}
class SonWidget extends StatelessWidget {
SonWidget({Key key, this.isActive, this.tapFunction}) : super(key: key);
final bool isActive;
final Function tapFunction;
void _handleTap() {
tapFunction(!isActive);
}
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
child: Container(
width: 200,
height: 200,
color: isActive ? Colors.amber : Colors.blue,
),
onTap: _handleTap,
),
);
}
}
三. 混合管理
如果子组件是有状态组件, 那么它可被父组件管理, 也可以自己管理自己.那么可以根据状态的重要性采取不同的管理方式吗?? 可以!
混合管理可以简单理解为: 父组件接管子组件一部分状态, 子组件再自己管理一些仅与自己相关的状态
如下例: 框内颜色是父组件接管的 边框颜色是 自身管理的.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("混合管理"),
),
body: ParentsWidget(),
);
}
}
class ParentsWidget extends StatefulWidget {
@override
_ParentsWidgetState createState() => _ParentsWidgetState();
}
class _ParentsWidgetState extends State<ParentsWidget> {
bool _isActive = false; //这个状态是父组件管理的, 给子组件用
void _tapToChangeColor(v) {
setState(() {
_isActive = v; //父组件接管管理的状态在此更新
});
}
@override
Widget build(BuildContext context) {
return SonWidget(isActive: _isActive, tapFunction: _tapToChangeColor);
}
}
class SonWidget extends StatefulWidget {
final bool isActive;
final Function tapFunction;
SonWidget({Key key, this.isActive, this.tapFunction}) : super(key: key);
@override
_SonWidgetState createState() => _SonWidgetState();
}
class _SonWidgetState extends State<SonWidget> {
bool _borderHighLight = false; //这个状态是自己管理的
void _handleTap() {
widget.tapFunction(!widget.isActive); //这个状态是父组件管理的
setState(() {
_borderHighLight = !_borderHighLight; //自己管理的状态在此更新
});
}
@override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
child: Container(
width: 200,
height: 200,
child: Container(
color: widget.isActive ? Colors.amber : Colors.blueAccent,
),
decoration: BoxDecoration(
border: Border.all(
color: _borderHighLight ? Colors.blueAccent : Colors.amber,
width: 10)),
),
onTap: _handleTap,
),
);
}
}
四. 全局状态管理 (第三方provider库)
有时候, 可能有一个状态是整个APP都要用的 比如:账号状态 等.这就需要我们做全局状态管理了
全局状态管理由多种方法, 这里我们使用一种比较简单的
https://pub.dev/packages/provider#-readme-tab-
这里我只用了比较旧的版本
provider: ^2.0.1+1
用法:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
main() {
runApp(ChangeNotifierProvider<Counter>.value(
notifier: Counter(1),
child: MyApp(),
));
}
class Counter with ChangeNotifier {
int _count;
Counter(this._count);
void add() {
_count++;
notifyListeners();
}
void sub() {
_count--;
notifyListeners();
}
get count => _count;
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("全局状态管理(provide库)"),
),
body: FirstWidget(),
);
}
}
class FirstWidget extends StatefulWidget {
@override
_FirstWidgetState createState() => _FirstWidgetState();
}
class _FirstWidgetState extends State<FirstWidget> {
@override
Widget build(BuildContext context) {
return Center(
child: Column(
children: <Widget>[
Text(
"这里有一个公用状态数据:${Provider.of<Counter>(context)._count}",
style: TextStyle(fontSize: 30),
),
RaisedButton.icon(
onPressed: () {
print("object");
Provider.of<Counter>(context).add();
},
icon: Icon(Icons.add_box),
label: Text("增大")),
RaisedButton.icon(
onPressed: () {
Provider.of<Counter>(context).sub();
},
icon: Icon(Icons.low_priority),
label: Text("减小")),
RaisedButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SecondPage()));
},
icon: Icon(Icons.remove_red_eye),
label: Text("看一看下一页能不能改变")),
],
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Column(
children: <Widget>[
Text(
"这是'下一页',这里面看一下全局状态:${Provider.of<Counter>(context)._count}",
style: TextStyle(fontSize: 30),
),
RaisedButton.icon(
onPressed: () {
print("object");
Provider.of<Counter>(context).add();
},
icon: Icon(Icons.add_box),
label: Text("增大")),
RaisedButton.icon(
onPressed: () {
Provider.of<Counter>(context).sub();
},
icon: Icon(Icons.low_priority),
label: Text("减小")),
],
));
}
}
网友评论