当我们想在多个页面(组件/Widget)之间共享状态(数据),或者一个页面(组件/WIdget)的多个子组件之间共享状态(数据),这个时候我们就需要用Flutter中的状态管理来管理统一的状态(数据),实现不同组件间直接的传值和数据共享。
今天我们来介绍一下Flutter官方提供的状态管理解决方案——Provider。
首先,我们在pub.dev里面搜provider,然后按照文档在Fluter项目中配置依赖。
第二步,在lib目录下新增一个provider文件夹,然后在该文件夹内放我们的各个状态管理类。(本例中我们新建了一个Counter.dart)
第三步,实现上一步定义的状态管理类:
//Counter
import 'package:flutter/material.dart';
class Counter with ChangeNotifier {
int _count = 0;//在不同组件之间共享的状态
/**
* 定义一个get方法,在外界获取私有状态值
*/
int get count => _count;
//增加数量(更新状态)
incCount(){
print(_count);
this._count++;
//表示更新状态.它会重新触发所有监听了该Provider的类的build方法
//在本例中,当notifyListeners方法执行的时候,购物车页面与我的页面的build方法都会被重新触发
notifyListeners();
}
}
第四步,在main.dart里面配置全局监听。
//main.dart
import 'package:flutter_jdshop/provider/Counter.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MultiProvider(
//在MaterialApp外层嵌套一个MultiProvider
providers: [
/** 在这里面配置全局监听的类*/
ChangeNotifierProvider(builder: (_) => Counter()),
],
child: MaterialApp(
initialRoute: "/", //初始路由
onGenerateRoute: prefix0.onGenerateRoute, //配置路由
theme: ThemeData(
primaryColor: Colors.white, //导航栏背景颜色
),
debugShowCheckedModeBanner: false, //取出右上角DEBUG
),
);
}
}
第五步,在对应的页面实现状态的获取与更新。如下是我分别在“购物车”页面和“我的”页面里面进行数量更新与获取的演示。
“购物车”页面更新数据:
import 'dart:developer';
import 'package:flutter_jdshop/provider/Counter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_jdshop/services/ScreenAdaptation.dart';
import 'package:provider/provider.dart';
class ShoppingCartPage extends StatefulWidget {
ShoppingCartPage({Key key}) : super(key: key);
_ShoppingCartPageState createState() => _ShoppingCartPageState();
}
class _ShoppingCartPageState extends State<ShoppingCartPage> {
@override
Widget build(BuildContext context) {
ScreenAdaptation.init(context);
//获取Provider对象
var counterProvider = Provider.of<Counter>(context);
return Scaffold(
appBar: _buildAppBarWidget(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
//更新状态
counterProvider.incCount();
},
),
body: Center(
//获取Provider的状态值
child: Text("购物车页面:${counterProvider.count}",
style: TextStyle(fontSize: 20)),
),
);
}
}
“我的”页面获取数据:
import 'package:flutter/material.dart';
import 'package:flutter_jdshop/provider/Counter.dart';
import 'package:provider/provider.dart';
class UserPage extends StatefulWidget {
UserPage({Key key}) : super(key: key);
_UserPageState createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
@override
Widget build(BuildContext context) {
//获取Provider对象
var counterProvider = Provider.of<Counter>(context);
return Scaffold(
appBar: AppBar(
title: Text("用户页面"),
),
body: Center(
//获取Provider的状态值
child: Text("用户页面,${counterProvider.count}",
style: TextStyle(fontSize: 20))),
);
}
}
到此为止,使用Provider进行状态管理的步骤就说完了,上面代码的演示效果如下:
上面我介绍了使用Provider进行状态管理的步骤,以及演示了一个实例。接下来我们考虑一个问题。
上例中的状态管理类Counter中的状态值_count,初始化该值的时候,如果该初始值不需要计算,我们在声明_count的时候进行初始赋值即可,如下:
class Counter with ChangeNotifier {
//在这里进行初始赋值
int _count = 0;//在不同组件之间共享的状态
/**
* 定义一个get方法,在外界获取私有状态值
*/
int get count => _count;
//增加数量(更新状态)
incCount(){
print(_count);
this._count++;
notifyListeners();//表示更新状态
}
}
但是如果该初始值需要计算得到,那么我们可以在Counter的构造函数中进行该计算。因为我们需要在main.dart中配置全局监听的类(这里是Counter类),配置的时候需要实例化该类(Counter),也就是会触发Counter的构造函数。
实例
第1步,定义一个状态管理类Cart:
import 'package:flutter/material.dart';
class Cart with ChangeNotifier {
List _productList = [];
List get productList => this._productList;
int get productNum => this.productList.length;
//增加商品
addProduct(productName){
this.productList.add(productName);
notifyListeners();
}
//删除商品
deleteProduct(){
this.productList.removeLast();
notifyListeners();
}
}
第2步,在main.dart里面配置全局监听:
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MultiProvider(
//在MaterialApp外层嵌套一个MultiProvider
providers: [
/** 在这里面配置全局监听的类*/
ChangeNotifierProvider(builder: (_) => Counter()),
ChangeNotifierProvider(builder: (_) => Cart()),
],
child: MaterialApp(
initialRoute: "/", //初始路由
onGenerateRoute: prefix0.onGenerateRoute, //配置路由
theme: ThemeData(
primaryColor: Colors.white, //导航栏背景颜色
),
debugShowCheckedModeBanner: false, //取出右上角DEBUG
),
);
}
}
第3步,在对应的页面实现状态的获取与更新。
在购物车页面更新与获取状态:
@override
Widget build(BuildContext context) {
ScreenAdaptation.init(context);
//获取Provider对象(Cart)
var cartProvider = Provider.of<Cart>(context);
return Scaffold(
appBar: _buildAppBarWidget(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
//更新状态(给购物车列表增加数据)
cartProvider.addProduct("山核桃");
},
),
body: ListView(
children: <Widget>[
CartPage(),
Divider(height: 5),
//获取Provider的状态值(购物车中商品数量)
Text("数量:${cartProvider.productNum}"),
],
),
);
}
在封装的购物车商品展示组件CartPage中获取provider状态:
import 'package:flutter/material.dart';
import 'package:flutter_jdshop/provider/Cart.dart';
import 'package:provider/provider.dart';
class CartPage extends StatefulWidget {
CartPage({Key key}) : super(key: key);
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
@override
Widget build(BuildContext context) {
//获取Provider对象
var cartProvider = Provider.of<Cart>(context);
return Column(
//获取Provider的状态值(购物车中的商品)
children: cartProvider.productList.map((value) {
return ListTile(
title: Text(value),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: (){
//修改Provider的状态值(删除)
cartProvider.deleteProduct();
},
),
);
}).toList(),
);
}
}
以上的效果如下:
以上。