0
点赞
收藏
分享

微信扫一扫

flutter之provider使用与简单封装

Provider是目前Google推荐的状态管理库,国内镜像的地址,现在的最新版本是4.1.1,但是我的sdk版本是1.16,不支持这个最新的,所以改版本用的4.0.0

基本使用

我先是以最简单的主题更改来做基本的更改

第一步,添加Provider依赖,pubspec.yaml

dependencies:
provider: ^4.0.0

第二步,创建Model

import 'package:flutter/material.dart';

class ThemeModel with ChangeNotifier {
ThemeData themeData = light();

bool lighted = true;

changeTheme() {
if (lighted) {
themeData = dark();
} else {
themeData = light();
}
lighted = !lighted;

notifyListeners();
}

static ThemeData light() {
return ThemeData(
textTheme: TextTheme(
subtitle1: TextStyle(
color: Colors.black,
fontSize: 16,
)),
backgroundColor: Colors.white,
brightness: Brightness.light,
primaryColor: Color(0xff248bfe),
appBarTheme: AppBarTheme(
elevation: 0,
textTheme: TextTheme(
subtitle1: TextStyle(
color: Colors.white,
fontSize: 16,
)),
),
);
}

ThemeData dark() {
return ThemeData(
textTheme: TextTheme(
subtitle1: TextStyle(
color: Colors.white,
fontSize: 16,
)),
backgroundColor: Colors.black,
brightness: Brightness.dark,
primaryColor: Color(0xff000000),
appBarTheme: AppBarTheme(
elevation: 0,
textTheme: TextTheme(
subtitle1: TextStyle(
color: Colors.white,
fontSize: 16,
)),
),
);
}
}

一个白天模式一个夜间模式,数据需要混入ChangeNotifier,数据更改后需要调用notifyListeners();来发出通知。

第三步,使用ChangeNotifierProvider

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context1) {
return ChangeNotifierProvider<ThemeModel>(
create: (_)=>new ThemeModel(),
child: //这里必须用Builder,因为Provider.of<ThemeViewModel>(context,listen: true)要拿这里传入的context
Builder(
builder: (context)=>
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: Provider.of<ThemeModel>(context,listen: true).themeData,//通过Provider.of取值
routes: <String,WidgetBuilder>{
"main/mainpage":(BuildContext context1)=>new MainPage(), //为什么这里可以拿到context1,provider就不行呢???因为该context中并没有Provider
},
home: SplashPage(),
)
),
);

}
}

  • ChangeNotifierProvider提供数据,如果用Provider以后取的的model就感受不到变化了
  • child需要传入Builder,因为外层build方法的context把当前model没有包含进去,所以需要用build来取含有此modelcontext.
  • 通过Provider.of取到对应的model

第四步,通过点击按钮,获取model并更改模式

InkWell(
onTap: (){
Provider.of<ThemeModel>(context,listen:false).changeTheme();
},
child: Icon(Icons.cake),
)

简单的封装

用provider对数据更改来刷新界面时,我们需要有效的控制数据的范围,如果全部放在最上层肯定会影响性能及数据的安全性。所以我们需要对provider写一个通用的组件,方便我们使用。

ProviderWidget封装

import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';

class ProviderWidget<T extends ChangeNotifier> extends StatefulWidget{
final T model;
final Widget Function(BuildContext context, T value, Widget child) builder;
final Function(T) onReady;

ProviderWidget({this.model,this.onReady,this.builder});

@override
_ProviderWidgetState<T> createState() => _ProviderWidgetState<T>();
}

class _ProviderWidgetState<T extends ChangeNotifier> extends State<ProviderWidget<T>> {
@override
void initState() {
super.initState();
if(widget.onReady!=null){
widget.onReady(widget.model);
}
}

@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T>(
create: (_) => widget.model,
child: Consumer<T>(//因为child
builder: widget.builder,
),
);
}
}
  • 泛型T是我们model的类型
  • builder是生成childbuilder, 不直接传入child还是因为之前说过的原因,构造对象的context需要是含有当前modelcontext才能取到此model,不然后报错。
  • 为了能取到context,我们此处用到了Consumer,合理的用Consumer可以减少刷新范围,这个类的具体说明请参考使用Provider前你应了解Consumer

使用示例

model类

class TestModel with ChangeNotifier {
int clickNum=0;

void add() {
clickNum++;
notifyListeners();
}
}

用widget的地方直接使用

ProviderWidget<TestModel>(
model:TestModel(),
onReady:(model){
model.toString();
},
builder:(context, model, child){
return Column(
children: <Widget>[
Text("${model.clickNum}"),
RaisedButton(child:Text("add"),onPressed: (){
model.add();
})
],
);
},
)

本文完整源码请移步github

举报

相关推荐

0 条评论