前文
本文所提供的的状态管理的方法为provide以及provider这两种,后续如果我使用了redux或state的话,就再来给大家分享
Flutter状态持久化
目的
:
在我们日常开发中,每次点击tab页面后,都会出现从新加载当前页面内容的现象,这种体验给用户看来很不友好,所以我们这里就需要用到了Flutter状态持久化。
两种状态持久化的方法
IndexedStack
原理:将所有的页面都放到IndexStack当中,通过控制index属性,来显示哪个页面(前端的小伙伴可以利用z-index来理解)
弊端:每一次加载APP的时候,都要将所有的页面加载出来,才能达到页面保持状态的效果
如何使用?
在你的bottomNavigationBar页面中,我们的body本来是控制显示首页的,现在我们用IndexedStack替换一下,下图中的pageList是我的页面数组
AutomaticKeepAliveClientMixin
结合tab切换保持页面状态相比IndexedStack而言配置起来稍微有些复杂,是结合BottomNavigationBar保持页面状态的时候进行配置的
原理:还没搞懂。。。。。
如何使用?
这里说明一下,如果用PageView包裹住的话,tab页切换就会有滑动切换的效果,所以这里我们要设置一下onPageChanged方法,这样底部标签栏就可以跟随切换而高亮了,下图中由于疏忽忘记写了,特附赠这段代码
body: PageView(
controller: this._pageController,
children: this.pageList,
onPageChanged: (index){
setState(() {
this._currentIndex = index;
});
},
),
OK,到此为止了, 状态化管理目前就这两种,大多数使用的是第二种,推荐第二种!
Flutter状态管理之Provide
flutter_provide是Google项目下的状态管理,推荐使用这个插件
关于Flutter的状态管理,我是用前端的Vuex
去理解的,是将UI层和逻辑层分开的操作。
如何使用?
首先你要做的是在pubspec.yaml
引入provide
插件。
provide: ^1.0.2 #状态管理
安装完毕后,我们就可以使用了,首先要写个状态管理类,也就是逻辑层的类
,我创建的文件名为test.dart
test.dart
import 'package:flutter/material.dart';
// 将页面的业务逻辑 分到当前dart文件中
// ChangeNotifier 不限制类的获取,谁都可以获取当前类
class Counter with ChangeNotifier {
int currentIndex = 0;
int index = 0;
changeIndex(index){
currentIndex = index;
// 可以通知听众。局部刷新Widget
notifyListeners();
}
increment(){
index++;
notifyListeners();
}
}
创建好类之后,我们就将该状态管理引入到我们的main.dart
入口文件当中,同时记得要引入provide插件
import 'package:provide/provide.dart'; // 状态管理
import 'package:project/provide/test.dart';
引入进来后,我们来将该类以及provide实例化,这里需要注意的是,实例化的时候是Providers(),并不是Provider(),最后在runApp()当中将provider注册进去
void main() {
var counter = Counter();
var providers = Providers();
// 如果想添加新的状态管理,在下面通过..添加就行
providers..provide(Provider<Counter>.value(counter))
runApp(ProviderNode(child:MyApp(), providers:providers));
}
好了,现在我们准备工作已经完事了,接下来我们来看看如何使用吧
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import 'package:project/provide/BottomNavigation.dart';
class MessagePage extends StatefulWidget {
@override
_MessagePageState createState() => _MessagePageState();
}
class _MessagePageState extends State<MessagePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Text('消息')
ShowText(),
Button()
],
),
)
);
}
}
class ShowText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Provide<Counter>(
// counter 是自定义逻辑类
builder: (context, child, counter){
return Text(
'${counter.index}',
style: Theme.of(context).textTheme.display1,
);
},
)
);
}
}
class Button extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text('增加'),
onPressed: (){
// 调用改变状态方法
Provide.value<Counter>(context).increment();
},
);
}
}
代码分析:
在我们需要保持状态管理的地方,利用Provider控件包裹起来,在调用builder方法 将控件返回出来,里面有三个参数,第一个是上下文,第二个是子类,第三个是状态管理类,我们通过第三个参数就可以访问到我们的属性值了,改变的方法也是通过value方法来调用管理类定义好的方法,这里的value记得声明泛型来指明我们的状态管理类。
Flutter状态管理之Provider
provider
是也是在谷歌项目下的状态管理,作用和provide
都是一样的,用于管理全局的数据状态
如何使用?
首先你要做的是在pubspec.yaml
引入provider
插件。
provider: ^3.2.0
创建自定义状态管理类Count.dart
import 'package:flutter/material.dart';
class Counter with ChangeNotifier{
int _count; // 状态
// 实例化时就初始化数据
Counter(){
this._count = 0;
}
int get count=>_count; // 获取当前状态(为什么已经有个变量了,还要再写一个变量赋值抛出去呢: 保护变量,避免状态管理类被污染)
incCount(){
this._count++;
notifyListeners(); // 通知更新状态
}
}
在main.dart
中使用MultiProvider控件包裹住所有内容,同时设置属性providers
进行监听状态管理
import 'package:flutter/material.dart';
import 'package:test_03/router/routes.dart'; // 自定义路由
import 'package:provider/provider.dart'; // 状态管理
import 'package:test_03/provider/Count.dart'; // 自定义状态管理
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_)=>Counter()), // 监听自定义的类
],
child: MaterialApp(
initialRoute: '/',
routes: routers,
onGenerateRoute: onGenerateRoute,
),
);
}
}
接下来就是在各个类中使用了,由于已经在main.js中用控件包裹住一层了,所以不需要像provide
一样,还需要再次嵌套控件了,只需要在您需要使用的类中引入您的provider
插件以及自定义的状态管理类
就可以了。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_03/provider/Count.dart';
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
String data = "init";
@override
Widget build(BuildContext context) {
// 是泛型指定自定义状态类
var counterProvider = Provider.of<Counter>(context);
return Scaffold(
body: ListView(
children: <Widget>[
Text(data),
Text('${counterProvider.count}'),
RaisedButton(
child: Text('点击修改状态管理中的数据'),
onPressed: (){
counterProvider.incCount();
},
),
],
),
}
}
同理如果别的页面也需要这个状态数据,就像这样引入就可以共用了
provider和provide的区别
1、作者
provide
:Flutter早期没有自己的状态管理类,由Google的一名开发人员开发写出的一款插件
provider
:Flutter官方团队提供的官方插件
2、使用
provide
:
(1)需要在main.dart
中的void main(){ }主函数方法中进行初始化和注册。
(2)各个dart类使用的时候需要在外层再次包裹一层Provide的控件
provider
:
(1)只需在main.js中的主控件外部包裹一层MultiProvider
控件,把providers
声明好属性就可以在内部使用了。
在自定义状态管理类时,都是混合使用的flutter内部提供的ChangeNotifier类,在通知时都是使用的notifyListeners()方法
OK! 彻底完结,有问题@我哦,告辞┏(^0^)┛