??Flutter中頁面沒有像Android、IOS 定義那么明確,Android中就是 Activity,IOS 中就是 UIViewController。
??在Flutter中,幾乎所有東西都是Widget。
將Widget視為可視組件(或與應用程序的可視方面交互的組件)。
??在項目開發(fā)中基本都會有一個 BaseActivity/BaseVIewController,封裝一些基本操作及公共部分,參照Android/IOS中 BaseActivity/BaseVIewController實現(xiàn),在 Flutter也實現(xiàn)同樣功能的 抽象的BaseWidget。
實現(xiàn)功能
- 開發(fā)頁面時,寫一個類繼承 BaseWidget,就會提示必須要實現(xiàn)的抽象方法,俗稱模板模式,要做的事情一目了然。這里將要寫的代碼定義成一個 Live Templates。
- 導航欄AppBar可以輕松隱藏和設置背景顏色(圖片),其中包含導航欄中的左邊返回鍵、中間的標題、右面的按鈕或文本,可以隨意設置隱藏和現(xiàn)實,當然可以重寫他們的方法,隨意設置自己的Widget,實現(xiàn)高度定制。
- 內置了一個錯誤頁面 ,主要用于網(wǎng)絡加載出錯或服務器返回錯誤的時候 ,可以直接調方法就顯示,不用每個頁面都寫錯誤頁面,避免需求變更時束手無策。
- 內置一個無數(shù)據(jù)頁面,用于列表無數(shù)據(jù)時展示。使用方法和功能和錯誤頁面差不多。
- 內置一個loading加載頁面,主要用于進入頁面時顯示一個 loading 視圖,默認進入界面就顯示,數(shù)據(jù)加載完成,顯示正常內容視圖,加載失敗話,就顯示上面定義的錯誤視圖。
- 進入自動調用 queryData 進行網(wǎng)絡請求。
- 內置了安全鍵盤,在要使用安全鍵盤頁面,初始化一下就可以了。
- 。。。
- 有了基類,以后拓展就很方面(如:返回刷新等)。
實現(xiàn)思路
??BaseWidget 是一個有狀態(tài)的基礎 Widget,由兩部分組成。
- Widget 定義
abstract class BaseWidget extends StatefulWidget {
@override
BaseWidgetState createState() => getState();
///子類實現(xiàn)
BaseWidgetState getState();
}
此部分在Widget的生命周期內不會發(fā)生變化,但可以接受可由其相應的State實例使用的參數(shù),當需要將其添加到窗口上時,可以通過實例化來實現(xiàn)。
- Widget State 定義
abstract class BaseWidgetState<T extends BaseWidget> extends State<T> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
...
}
}
此部分是在Widget的生命周期中變化的部分,并強制每次應用修改時重建Widget的這個特定實例。
此兩部分別被子類繼承,并要求實現(xiàn)其抽象方法,getState 用于創(chuàng)建繼承BaseWidgetState的子類 Widget State實例。
布局搭建
在 BaseWidgetState 中內置了標題欄、錯誤視圖、空頁面視圖、加載中視圖、安全鍵盤等幾個基本控件,預留一個抽象方法buildWidget給子類搭建自己的布局。
@override
Widget build(BuildContext context) {
return _hasSecurityKeyboard
? _buildWidgetWithKeyboard()
: _buildWidgetDefault();
}
///構建默認視圖
Widget _buildWidgetDefault() {
///使用appbar,也可直接只有 body 在 body 里自定義狀態(tài)欄、標題欄
return WillPopScope(
child: Scaffold(
appBar: _buildAppBar(),
body: _buildBody(),
),
onWillPop: _requestPop,
);
}
///構建包含安全鍵盤視圖
Widget _buildWidgetWithKeyboard() {
///WidgetsApp或者MaterialApp,Flutter會自動默認創(chuàng)建一個Navigator
///用于鍵盤彈出的時候頁面可以滾動到輸入框的位置
return WillPopScope(
child: KeyboardMediaQuery(
child: Builder(builder: (ctx) {
///初始化鍵盤監(jiān)聽并且傳遞當前頁面的context
KeyboardManager.init(ctx);
return Scaffold(
appBar: _buildAppBar(),
body: _buildBody(),
);
}),
),
onWillPop: _requestPop,
);
}
///物理返回
Future<bool> _requestPop() {
bool b = true;
if (KeyboardManager.isShowKeyboard) {
KeyboardManager.hideKeyboard();
b = false;
}
return Future.value(b);
}
///子類實現(xiàn),構建各自頁面UI控件 相當于setContentView()
Widget buildWidget(BuildContext context);
///構建內容區(qū)
Widget _buildBody() {
return Container(
///內容區(qū)背景顏色
color: LcfarmColor.colorF8F9F8,
child: Stack(
children: <Widget>[
Offstage(
offstage: !_isContentWidgetShow,
child: buildWidget(context),
),
_buildErrorWidget(),
_buildEmptyWidget(),
_buildLoadingWidget(),
],
),
);
}
- 通過 _hasSecurityKeyboard控制是否內置安全鍵盤,子類可以在 initState中通過初始化該字段來實現(xiàn)。
- 同樣錯誤視圖、空白視圖、加載中視圖提供方法讓子類控制是否顯示,以及設置相應的文字、圖片等。
使用方法
- 基本實現(xiàn)代碼如下:
class Test extends BaseWidget {
@override
BaseWidgetState getState() {
return _TestState();
}
}
class _TestState extends BaseWidgetState<Test> {
@override
Widget buildWidget(BuildContext context) {
return Container();
}
@override
void queryData() {
}
}
- getState 返回繼承BaseWidgetState的 Widget State。
- buildWidget 用于構建當前視圖
- queryData用于是否進入查詢數(shù)據(jù)
如有查詢,則直接調用網(wǎng)絡請求即可。
@override
void queryData() {
_loadData(...)
}
如無需查詢數(shù)據(jù),則禁用掉即可。
@override
void queryData() {
///進入無需網(wǎng)絡請求數(shù)據(jù)
disabledLoading();
}
- 顯示成功視圖、錯誤視圖、空白視圖
void _loadData(LoadType type) {
AccountService.letterList(
pageNo,
(Pager<LetterModel> pager) {
///暫無數(shù)據(jù)
if (pager.total == 0) {
showLoadEmpty();
return;
}
pageNo = pager.currentPage;
if (type == LoadType.loadMore) {
letterModels.addAll(pager.list);
} else {
letterModels = pager.list;
}
showLoadSuccess();
},
(HttpError error) {
showLoadFailure(error.code, error.message);
},
);
}
最后
??如果在使用過程遇到問題,歡迎下方留言交流。