[toc]
Flutter從入門到奔潰(五):擼一些UI交互以及動態(tài)頁面
前記
我們之前粗略介紹了基礎(chǔ)以及布局:
Flutter從入門到奔潰(一):擼一個登錄界面
Flutter從入門到奔潰(二):擼一個個人界面
Flutter從入門到奔潰(三):擼一個App基礎(chǔ)框架
# Flutter從入門到奔潰(四):擼一個包含列表刷新以及網(wǎng)絡(luò)請求的首頁
總算是脫離了無聊的靜態(tài)頁面,涉及到了一部分網(wǎng)絡(luò)交互爽雄,今天我們接著進(jìn)行UI交互的學(xué)習(xí)(因?yàn)殚_源中國的api感覺不太好用洞坑,我們改用wananzhuo的api迟杂,這個也是我們安卓狗練手的必備項目了排拷,這里感謝鴻洋大神)。
頁面交互
登錄界面
登錄界面使用我們之前繪制的靜態(tài)頁面布蔗,在這里我們進(jìn)行UI交互:
- 拿到用戶輸入的數(shù)據(jù)
- 對數(shù)據(jù)進(jìn)行必要的驗(yàn)證
- 提交用戶數(shù)據(jù)到后臺
- 根據(jù)接口成功與否進(jìn)行頁面交互以及數(shù)據(jù)更新
接下來我們分步進(jìn)行上述操作:
拿到用戶輸入的數(shù)據(jù)
我們頁面是用了基礎(chǔ)的TextField,所以我們通過controller來進(jìn)行數(shù)據(jù)獲取泽谨,(如果是用form表單的格式的話,還有另外一種方式骨杂,在onsave方法里面保存搓蚪,這里按下不表)丁鹉。
onPressed: () {
_postLogin(
_userNameController.text, _userPassController.text);
},
我們很容易可以知道上述代碼的作用是通過2個對應(yīng)的controller拿到了username,userpass2個參數(shù)杜耙,并把他們作為參數(shù)提供給了私有方法_postLogin。
對數(shù)據(jù)進(jìn)行必要的驗(yàn)證
這里對數(shù)據(jù)并沒有太大的要求记靡,只要是非空摸吠,我們就默認(rèn)是有效數(shù)據(jù),所以我們做了簡單的判斷:
_postLogin(String userName, String userPassword) {
if (userName.isNotEmpty && userPassword.isNotEmpty) {
// do some
} else {
TsUtils.showShort('請輸入用戶名和密碼');
}
}
這里我們稍微講下使用的一個插件:** fluttertoast: ^2.0.7**呀洲,很明顯就是一個android的Toast方法啼止,(這里還有另外一種做法是用原生提供橋接献烦,讓flutter調(diào)用原生方法進(jìn)行交互,這里也按下不表吏夯,后續(xù)我們更新這部分的內(nèi)容)即横,
import 'package:fluttertoast/fluttertoast.dart';
class TsUtils{
static showShort(String msg){
Fluttertoast.showToast(
msg: msg,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
bgcolor: "#63CA6C",
textcolor: '#ffffff'
);
}
}
提交用戶數(shù)據(jù)到后臺
玩安卓的api接口是典型的三段式接口:
{
"data": ...,
"errorCode": 0,
"errorMsg": ""
}
- 判斷成功與否用errorCode
- 顯示信息用errorMsg
- 拿數(shù)據(jù)用data
所以我們對應(yīng)進(jìn)行了比較拙略的封裝:
// post請求
static Future<Map> post(String url,
{Map<String, String> params, bool saveCookie = false}) async {
if (params == null) {
params = new Map();
}
String _url = Api.BASE_URL + url;
if (OsApplication.cookie != null) {
params['Cookie'] = OsApplication.cookie;
}
http.Response res = await http.post(_url, body: params);
return _dealWithRes(res, saveCookie: saveCookie);
}
static Map<String, dynamic> _dealWithRes(var res, {bool saveCookie}) {
if (res.statusCode == 200) {
var cookie = res.headers['set-cookie'];
if (saveCookie) {
SpUtils.saveCookie(cookie);
OsApplication.cookie = cookie;
}
String body = res.body;
var jsonStr = json.decode(body);
print('the jsonStr is $jsonStr');
int errCode = jsonStr['errorCode'];
if (errCode == 0) {
var data = jsonStr['data'];
return data;
} else {
TsUtils.showShort(jsonStr['errorMsg']);
return null;
}
} else {
TsUtils.showShort('您的網(wǎng)絡(luò)好像不太好喲~~~///(^v^)\\\~~~');
return null;
}
}
這里需要注意的是一個**cookie **跺嗽,我們用來進(jìn)行登錄的憑證,這里的思路是:
- 登錄的時候拿到cookie陈醒,保存到OsApplication類中钉跷,并且持久化
- 啟動app的時候從持久化中獲取肚逸,保存到OsApplication類中,
- 調(diào)用接口的時候根據(jù)是否要保存膝晾,重新進(jìn)行保存务冕,并攜帶cookie傳到后臺
(存在一個問題是內(nèi)存被殺死后禀忆,要重新從持久化中獲取)
我們完整的登錄方法應(yīng)該是:
_postLogin(String userName, String userPassword) {
if (userName.isNotEmpty && userPassword.isNotEmpty) {
Map<String, String> params = new Map();
params['username'] = userName;
params['password'] = userPassword;
Http.post(Api.USER_LOGIN, params: params,saveCookie: true).then((result) {
SpUtils.map2UserInfo(result).then((userInfoBean){
if(userInfoBean!=null){
OsApplication.eventBus.fire(new LoginEvent(userInfoBean.username));
SpUtils.saveUserInfo(userInfoBean);
Navigator.pop(context);
}
});
});
} else {
TsUtils.showShort('請輸入用戶名和密碼');
}
}
這里我們是不是看到了一個熟悉的名詞呢=> eventBus,hahahahahahahahhahahahahhaha,它是我們下一個步驟的主角。
根據(jù)接口成功與否進(jìn)行頁面交互以及數(shù)據(jù)更新
我們登錄后戴涝,要怎么通知其他頁面啥刻,我已經(jīng)登錄了呢?
- 把棧里所有activity都出棧府喳,重新new出新的帶登錄信息的activity再壓棧進(jìn)去
- 通過其他手段通知需要更新狀態(tài)的頁面:爺爺我登錄了蘑拯,你趕緊地更新頁面I昃健!
我覺得第二種比較劃算碎捺!而在安卓中,我們可以通過原生的廣播晋柱,第三方的EventBus來實(shí)現(xiàn)诵叁,而在flutter,我們可以考慮用插件event_bus: ^1.0. 1來實(shí)現(xiàn)碑诉。
它的實(shí)現(xiàn)方式和安卓版的類似:
- 寫event類
- 事件源發(fā)出event
- 接受源接受event进栽,并作出對應(yīng)處理
登錄事件源發(fā)出消息
OsApplication.eventBus.fire(new LoginEvent(userInfoBean.username));
個人中心接受源接收消息
OsApplication.eventBus.on<LoginEvent>().listen((event) {
setState(() {
if (event != null && event.userName != null) {
userName = event.userName;
userAvatar = 'http://www.wanandroid.com/resources/image/pc/logo.png';
} else {
userName = null;
userAvatar = null;
}
});
});
設(shè)置頁面-退出登錄發(fā)送logout事件源
這里不能說用戶一點(diǎn)退出就立馬噌噌噌地退出了快毛,要有一個交互的過程--AlertDialog署照,
_showDialog() {
showDialog(
builder: (context) => new AlertDialog(
title: new Text('提示'),
content: new Text('是否要退出登錄'),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: new Text('取消')),
new FlatButton(
onPressed: () {
SpUtils.cleanUserInfo();
OsApplication.eventBus.fire(new LoginEvent(null));
Navigator.pop(context);
},
child: new Text('是的'))
],
),
context: context);
}
在確定按鈕中建芙,我們清除了用戶信息(包括保存保存于內(nèi)存和持久化的userName,token,id,cookie)懂扼,
并且發(fā)出了一個null的event阀湿,由接受源代碼可以知道,會顯示未登錄狀態(tài)映砖。
丑丑的體系頁面
UI “鑒賞”
接下來做好準(zhǔn)備T职ぁ@统巍! 你將會受到視覺的沖擊D!!三娩! 一大波鋼鐵直男的粗糙審美將會沖擊你妹懒!
我很自豪地認(rèn)為要是有審美選丑比賽,我肯定可以奪得第一滔悉!
頁面拆解
一級頁面
一級頁面沒有什么難度,我們?nèi)匀挥卸喾N方案來實(shí)現(xiàn)它:
- listView
- CustomScrollView
- ScrollView
這里我們選用CustomScrollView歉提,具體代碼可以:
體系頁面
如果有人有興趣的話区转,可以試試自己動手寫一個呢。
二級頁面
二級頁面用安卓來實(shí)現(xiàn)肯定就是:tabLayout+ViewPager侄泽,有趣的是flutter只用一個控件就可以實(shí)現(xiàn)了DefaultTabController
@override
Widget build(BuildContext context) {
widgetsUtils = new WidgetsUtils(context);
return new Scaffold(
appBar: new AppBar(
title: widgetsUtils.getAppBar(_title),
iconTheme: new IconThemeData(color: Colors.white),
),
body: new DefaultTabController(
child: new Scaffold(
appBar: new TabBar(
isScrollable: true,
tabs: _initTabs(),
),
body: new TabBarView(children: _initBody())),
length: classList.length,
),
);
}
其中的TabBar類似于tabLayout;
其中的TabBarView類似于ViewPager;
這里有一個需要注意的點(diǎn)悼尾,TabBarView的children每次劃到的時候都會重新走一次initState(),而如果我們在那里請求接口的話闺魏,就會每次都請求一次俯画,這樣無論是UI還是性能還是體驗(yàn)都不是我們要的
而解決方案是在children(也就是類似fragment)的State加上 with AutomaticKeepAliveClientMixin
class _SystemChildPageState extends State<SystemChildPage>
with AutomaticKeepAliveClientMixin{
@override
bool get wantKeepAlive => true;
}
見名知意艰垂,這個是用于標(biāo)志是否保持狀態(tài)的tag。
三級
三級沒了... 就一個webview
總結(jié)
陳詞
草草地說沮焕,好像也沒什么好寫了拉宗,接下去做的都是重復(fù)性的勞動:
- 接接口
- 寫數(shù)據(jù)
- 畫UI
但是
但是flutter不止這么些可以玩的,動畫魁巩,2端交互谷遂,其其他他零零總總的,還有很多好玩的控件畴嘶,嗯...接下來繼續(xù)慢慢玩flutter集晚。
互勉
一起玩吧