我們常常會遇到以下的場景:
頁面已打開,首先需要請求網(wǎng)絡,此時頁面展示加載中的視圖;
網(wǎng)絡請求完畢之后,會出現(xiàn)以下幾種情況:
- 遇到各種問題,出現(xiàn)加載失敗的情況,但是又可以重新加載
- 加載完后無數(shù)據(jù),需要展示無數(shù)據(jù)的屬兔
- 加載成功,展示需要展示的頁面
根據(jù)以上場景,我封裝了一個自定義組件來滿足以上要求
///四種視圖狀態(tài)
enum LoadState { State_Success, State_Error, State_Loading, State_Empty }
///根據(jù)不同狀態(tài)來展示不同的視圖
class LoadStateLayout extends StatefulWidget {
final LoadState state; //頁面狀態(tài)
final Widget successWidget;//成功視圖
final VoidCallback errorRetry; //錯誤事件處理
LoadStateLayout(
{Key key,
this.state = LoadState.State_Loading,//默認為加載狀態(tài)
this.successWidget,
this.errorRetry})
: super(key: key);
@override
_LoadStateLayoutState createState() => _LoadStateLayoutState();
}
class _LoadStateLayoutState extends State<LoadStateLayout> {
@override
Widget build(BuildContext context) {
return Container(
//寬高都充滿屏幕剩余空間
width: double.infinity,
height: double.infinity,
child: _buildWidget,
);
}
///根據(jù)不同狀態(tài)來顯示不同的視圖
Widget get _buildWidget {
switch (widget.state) {
case LoadState.State_Success:
return widget.successWidget;
break;
case LoadState.State_Error:
return _errorView;
break;
case LoadState.State_Loading:
return _loadingView;
break;
case LoadState.State_Empty:
return _emptyView;
break;
default:
return null;
}
}
///加載中視圖
Widget get _loadingView {
return Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(color: Colors.transparent),
alignment: Alignment.center,
child: Container(
height: 80,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Color(0x88000000), borderRadius: BorderRadius.circular(6)),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[CircularProgressIndicator(), Text('正在加載')],
),
),
);
}
///錯誤視圖
Widget get _errorView {
return Container(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'images/img/ic_error_page.png',
height: 80,
width: 100,
),
Text("加載失敗,請重試"),
RaisedButton(
color: Color(0xffbc2929),
onPressed: widget.errorRetry,
child: Text(
'重新加載',
style: TextStyle(color: Colors.white),
),
)
],
),
);
}
///數(shù)據(jù)為空的視圖
Widget get _emptyView {
return Container(
width: double.infinity,
height: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'images/img/ic_empty.png',
height: 100,
width: 100,
),
Padding(
padding: EdgeInsets.only(top: 10),
child: Text('暫無數(shù)據(jù)'),
)
],
),
);
}
}
使用方式
import 'package:flutter/material.dart';
import 'package:sah_flutter/ui/widgets/load_state_layout.dart';
class Test extends StatefulWidget {
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
//頁面加載狀態(tài),默認為加載中
LoadState _layoutState = LoadState.State_Loading;
@override
void initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('測試LoadStateLayout'),
),
body: LoadStateLayout(
state: _layoutState,
errorRetry: () {
setState(() {
_layoutState = LoadState.State_Loading;
});
loadData();
}, //錯誤按鈕點擊過后進行重新加載
successWidget: Center(
child: Text('加載成功'),
),
),
);
}
void loadData() {
//模擬網(wǎng)絡請求
Future.delayed(Duration(seconds: 2)).then((_) {
//此為加載結(jié)束
setState(() {
//如果加載結(jié)束后的數(shù)據(jù)為空,則狀態(tài)改為空
_layoutState = LoadState.State_Success;
});
}).catchError((_) {
//此為加載失敗
setState(() {
_layoutState = LoadState.State_Error;
});
});
}
}