1.Provider 全局状态管理
安装: pubspec.yaml
dependencies:
provider: ^3.0.0+1
引入:
import 'package:provider/provider.dart';
自定义Store: store.dart
import 'package:provider/provider.dart'
show ChangeNotifierProvider, MultiProvider, Consumer, Provider;
import 'model/storeData.dart' show UserInfo; //Model层
export 'model/storeData.dart'; //导出Model层
class Store {
static init({context, child}) {
//多个Provider
return MultiProvider(
providers: [
ChangeNotifierProvider(
builder: (_) => UserInfo(),
)
],
child: child,
);
}
//获取值 of(context) 这个会引起页面的整体刷新,如果全局是页面级别的
static T value<T>(context) {
return Provider.of<T>(context);
}
// 不会引起页面的刷新,只刷新了 Consumer 的部分,极大地缩小你的控件刷新范围
static Consumer connect<T>({builder, child}) {
return Consumer<T>(builder: builder, child: child);
}
}
Model层的定义:storeData.dart
import 'package:flutter/material.dart' show ChangeNotifier;
class UserInfo with ChangeNotifier {
String _name = "用户名";
String testData = "测试数据"; //尽量私有变量定义
String get name => _name;
void setName(name) {
_name = name;
notifyListeners(); //通知更新数据
}
@override
void dispose() {
super.dispose();
}
}
引用:
import 'package:flutter/material.dart';
import 'package:flutter_app/store.dart' show Store, UserInfo;
class MyIos extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _MyIos();
}
}
class _MyIos extends State<MyIos> {
@override
Widget build(BuildContext context) {
print("ios 更新");
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Layout"),
),
body: Column(
children: <Widget>[
Store.connect<UserInfo>(builder: (ctx, user, child) {
return Text(user.name);
}),
//这个会引起整个页面重新build
// RaisedButton(
// child: Text("修改数据"),
// onPressed: () {
// Store.value<UserInfo>(context).setName("234");
// },
// ),
Store.connect<UserInfo>(
builder: (ctx, user, child) {
return RaisedButton(
child: child,
onPressed: () {
user.setName("111");
},
);
},
child: Text("修改数据"))
],
),
);
}
}
配置: main.dart
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
//这里是整个app的全局变量
return Store.init(
context: context, //以这个为准
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
//注册路由
routes: {
"exp": (context) => Example(),
"txt": (context) => MyText(),
"btn": (context) => MyButton(),
"fm": (context) => Fm(),
"input": (context) => MyInput(),
"row": (context) => MyRow(),
"cons": (context) => MyCons(),
"dec": (context) => Dec(),
"container": (context) => Con(),
"list": (context) => MyList(),
"grid": (context) => MyGrid(),
"custom": (context) => MyCustom(),
"scroll": (context) => NocaScroll(),
"bar": (context) => MyBar(),
"pointer": (context) => MyPointer(),
"ges": (context) => MyGesture(),
"ani": (context) => MyAnimate(),
"hero": (context) => MyHero(),
"more": (context) => MorePage(),
"http": (context) => MyHttp(),
"check": (context) => MyCheck(),
"component": (context) => MyComponent(),
"ios": (context) => MyIos(),
},
home: MyHomePage(title: 'Flutter Demo Home Page'),
));
}
}
2.管理状态的最常见的方法
Widget管理自己的状态。
Widget管理子Widget状态。
混合管理(父Widget和子Widget都管理状态)。
如何决定使用哪种管理方法?下面是官方给出的一些原则可以帮助你做决定:
如果状态是用户数据,如复选框的选中状态、滑块的位置,则该状态最好由父Widget管理。
如果状态是有关界面外观效果的,例如颜色、动画,那么状态最好由Widget本身来管理。
如果某一个状态是不同Widget共享的则最好由它们共同的父Widget管理。
在Widget内部管理状态封装性会好一些,而在父Widget中管理会比较灵活。有些时候,如果不确定到底该怎么管理状态,那么推荐的首选是在父widget中管理(灵活会显得更重要一些)。
2-1. Widget管理自身状态
// TapboxA 管理自身状态.
//------------------------- TapboxA ----------------------------------
class TapboxA extends StatefulWidget {
TapboxA({Key key}) : super(key: key);
@override
_TapboxAState createState() => new _TapboxAState();
}
class _TapboxAState extends State<TapboxA> {
bool _active = false;
void _handleTap() {
setState(() {
_active = !_active;
});
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
_active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: _active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
2-2.父Widget管理子Widget的状态
// ParentWidget 为 TapboxB 管理状态.
//------------------------ ParentWidget --------------------------------
class ParentWidget extends StatefulWidget {
@override
_ParentWidgetState createState() => new _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//------------------------- TapboxB ----------------------------------
class TapboxB extends StatelessWidget {
TapboxB({Key key, this.active: false, @required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
void _handleTap() {
onChanged(!active);
}
Widget build(BuildContext context) {
return new GestureDetector(
onTap: _handleTap,
child: new Container(
child: new Center(
child: new Text(
active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white),
),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
),
);
}
}
2-3. 混合状态管理
对于一些组件来说,混合管理的方式会非常有用。在这种情况下,组件自身管理一些内部状态,而父组件管理一些其他外部状态
在下面TapboxC示例中,手指按下时,盒子的周围会出现一个深绿色的边框,抬起时,边框消失。点击完成后,盒子的颜色改变。 TapboxC将其_active状态导出到其父组件中,但在内部管理其_highlight状态。这个例子有两个状态对象_ParentWidgetState和_TapboxCState。
_ParentWidgetStateC类:
管理_active 状态。
实现 _handleTapboxChanged() ,当盒子被点击时调用。
当点击盒子并且_active状态改变时调用setState()更新UI。
_TapboxCState 对象:
管理_highlight 状态。
GestureDetector监听所有tap事件。当用户点下时,它添加高亮(深绿色边框);当用户释放时,会移除高亮。
当按下、抬起、或者取消点击时更新_highlight状态,调用setState()更新UI。
当点击时,将状态的改变传递给父组件
//---------------------------- ParentWidget ----------------------------
class ParentWidgetC extends StatefulWidget {
@override
_ParentWidgetCState createState() => new _ParentWidgetCState();
}
class _ParentWidgetCState extends State<ParentWidgetC> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return new Container(
child: new TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//----------------------------- TapboxC ------------------------------
class TapboxC extends StatefulWidget {
TapboxC({Key key, this.active: false, @required this.onChanged})
: super(key: key);
final bool active;
final ValueChanged<bool> onChanged;
@override
_TapboxCState createState() => new _TapboxCState();
}
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
void _handleTap() {
widget.onChanged(!widget.active);
}
@override
Widget build(BuildContext context) {
// 在按下时添加绿色边框,当抬起时,取消高亮
return new GestureDetector(
onTapDown: _handleTapDown, // 处理按下事件
onTapUp: _handleTapUp, // 处理抬起事件
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: new Container(
child: new Center(
child: new Text(widget.active ? 'Active' : 'Inactive',
style: new TextStyle(fontSize: 32.0, color: Colors.white)),
),
width: 200.0,
height: 200.0,
decoration: new BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? new Border.all(
color: Colors.teal[700],
width: 10.0,
)
: null,
),
),
);
}
}