初步接觸
剛開始接觸Provider的時候芦劣,感覺比較懵逼,因為之前連RN的狀態(tài)管理Redux都沒搞明白说榆,主要是覺得太繁瑣了吧虚吟。在使用Provider之前,看過一些BLOC,ScopeModel等框架签财,但是感覺起來還是Provider更好用吧串慰。Provider也是谷歌官方所推薦的。
學習Provider唱蒸,網上看到最多的是Counter計數(shù)器邦鲫。這里我們不講計數(shù)器,我們談一個項目中比較實際一點的的LoaderContainer (加載器)神汹。
首先庆捺,LoaderContainer是我編寫的一個加載器類
- LoaderContainer 加載器組件古今,聲明了加載器狀態(tài)值,加載器在不同狀態(tài)下呈現(xiàn)的視圖滔以。
import 'package:flutter/material.dart';
import 'package:project_name/core/widget/rounded_button.dart';
import 'package:project_name/data/app/app_constants.dart';
enum LoaderState { NoAction, Loading, Succeed, Failed, NoData }
class LoaderContainer extends StatefulWidget {
LoaderContainer({
Key key,
@required this.contentView,
this.loadingView,
this.errorView,
this.emptyView,
@required this.loaderState,
this.onReload,
}) : super(key: key);
final LoaderState loaderState;
final Widget loadingView;
final Widget errorView;
final Widget emptyView;
final Widget contentView;
final Function onReload;
@override
State createState() => _LoaderContainerState();
}
class _LoaderContainerState extends State<LoaderContainer> {
@override
Widget build(BuildContext context) {
Widget currentWidget;
switch (widget.loaderState) {
case LoaderState.Loading:
currentWidget = widget.loadingView ?? _ClassicalLoadingView();
break;
case LoaderState.Failed:
currentWidget = widget.errorView ??
_ClassicalErrorView(
onReload: () => widget.onReload(),
);
break;
case LoaderState.NoData:
currentWidget = widget.emptyView ?? _ClassicalNoDataView();
break;
case LoaderState.Succeed:
case LoaderState.NoAction:
currentWidget = widget.contentView;
break;
}
return currentWidget;
}
}
class _ClassicalLoadingView extends StatelessWidget {
@override
Widget build(BuildContext context) => Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(AppConstants.themeColor),
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
'正在拼命加載中...',
style: TextStyle(
fontSize: 13,
color: Color(0xff999999),
),
),
),
],
),
);
}
class _ClassicalErrorView extends StatelessWidget {
_ClassicalErrorView({@required this.onReload}) : super();
final Function onReload;
@override
Widget build(BuildContext context) => Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'asset/img/ic_default_load_data_failed.png',
width: 80,
height: 80,
color: Color(0xff999999),
),
Padding(
padding: const EdgeInsets.only(top: 12),
child: Text(
'加載失敗捉腥,請稍后點擊重試',
style: TextStyle(
fontSize: 13,
color: Color(0xff999999),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: RoundedButton(
bgColor: AppConstants.themeColor,
onPressed: onReload,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: Text(
'重新加載',
style: TextStyle(color: Theme.of(context).buttonColor),
),
),
),
),
],
),
);
}
class _ClassicalNoDataView extends StatelessWidget {
@override
Widget build(BuildContext context) => Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'asset/img/ic_default_load_data_failed.png',
width: 80,
height: 80,
color: Color(0xff999999),
),
Padding(
padding: const EdgeInsets.only(top: 0),
child: Text(
'暫無相關數(shù)據 /(ㄒoㄒ)/~~',
style: TextStyle(
fontSize: 13,
color: Color(0xff999999),
),
),
),
],
),
);
}
- 準備一個加載器狀態(tài)的Model,在Provider中醉者,要求變化的值能處理相關變化但狭,必須繼承相關類,如:ChangeNotifier(常用)等撬即。
import 'package:flutter/cupertino.dart';
import 'package:project_name/core/widget/loader_container.dart'
as LoaderStater;
/// 加載器的狀態(tài)Model類
class LoaderStateModel extends ChangeNotifier {
LoaderStater.LoaderState _state = LoaderStater.LoaderState.Loading;
/// 構造函數(shù)
LoaderStateModel([this._state]) {
this._state = this._state ?? LoaderStater.LoaderState.Loading;
}
/// 修改狀態(tài)
///
/// [state] LoaderState的取值
void changeState(LoaderStater.LoaderState state) {
_state = state;
notifyListeners();
}
/// 獲取當前加載器的狀態(tài)
LoaderStater.LoaderState get state => _state;
}
- 頁面中處理加載器狀態(tài), 首頁要給Page包裝一個Provider立磁,這里寫在跳轉這個頁面的方法處。
return MultiProvider(providers: [
ChangeNotifierProvider<LoaderStateModel>.value(
value: LoaderStateModel(LoaderState.Succeed))
], child: PresaleOrderDetailInfoPage());
- 之前包裝過Provider剥槐,那么在PresaleOrderDetailInfoPage中就能接收到Provider共享的狀態(tài)值了唱歧。一般情況下,我們接收值使用Provider.of<xxx>(context)來接收粒竖,如果只是接收值可以考慮使用Consumer或其相關擴展函數(shù)颅崩。
class PresaleOrderDetailInfoPage extends StatefulWidget {
PresaleOrderDetailInfoPage({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => _PresaleOrderDetailInfoPageState();
}
class _PresaleOrderDetailInfoPageState
extends BasePageState<PresaleOrderDetailInfoPage>
with TickerProviderStateMixin {
/// 加載狀體模型
LoaderStateModel _loaderStateModel;
/// 調用網絡獲取訂單詳情信息
void _getOrderDetailInfo() async {
_loaderStateModel.changeState(LoaderState.Loading);
Future.delayed(Duration(seconds: 3), () { //模擬數(shù)據調用
_loaderStateModel.changeState(LoaderState.Succeed);
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
/// 初始化加載器的狀態(tài)
final loaderStateModel =
Provider.of<LoaderStateModel>(context);
if (this._loaderStateModel != loaderStateModel) {
this._loaderStateModel = loaderStateModel;
Future.microtask(() => _getOrderDetailInfo()); //必須要這么做,不然可能會拋出異常蕊苗,使用Future.microtask執(zhí)行初始化任務
}
}
@override
Widget build(BuildContext context) => MaterialApp(
theme: ThemeData(primaryColor: Colors.white),
home: Scaffold(
appBar: _buildAppBar(),
backgroundColor: AppConstants.backgroundColor,
body: _buildContentView(context),
),
);
/// 構建AppBar視圖
Widget _buildAppBar() => AppBar(
backgroundColor: Colors.white,
title: Text('訂單詳情', style: TextStyle(color: Color(0xff333333))),
centerTitle: true,
elevation: 0.5,
leading: FlatButton(
child: Image.asset(_imageAssetPaths['NavigationBack'],
fit: BoxFit.contain, color: Color(0xff333333)),
padding: const EdgeInsets.all(20),
shape: CircleBorder(),
onPressed: () => finish(),
));
/// 構建頁面主視圖
Widget _buildContentView(BuildContext context) => Consumer<LoaderStateModel>( //使用Consumer處理共享值
builder: (context, state, _) => LoaderContainer(
loaderState: state.state,
onReload: _getOrderDetailInfo,
contentView: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildOrderHeaderView(),
_buildRefundProcessView(),
_buildReceiverAddressView(),
_buildGoodsInfoContainerView(),
_buildStaticsInfoContentView(),
],
),
),
),
_buildOperatorContainerView(),
],
),
),
);
///...省略一些不重要的代碼
}
最后沿后,希望各位學習這個框架的朋友們加油,我也還在更加熟悉這個框架朽砰。目前來說尖滚,已經嘗到這個框架所帶來的甜處了。