Flutter從入門到奔潰(五):擼一些UI交互以及動態(tài)頁面

[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迟杂,這個也是我們安卓狗練手的必備項目了排拷,這里感謝鴻洋大神)。

頁面交互

登錄界面

image.png

登錄界面使用我們之前繪制的靜態(tài)頁面布蔗,在這里我們進(jìn)行UI交互:

  1. 拿到用戶輸入的數(shù)據(jù)
  2. 對數(shù)據(jù)進(jìn)行必要的驗(yàn)證
  3. 提交用戶數(shù)據(jù)到后臺
  4. 根據(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": ""
}
  1. 判斷成功與否用errorCode
  2. 顯示信息用errorMsg
  3. 拿數(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)行登錄的憑證,這里的思路是:

  1. 登錄的時候拿到cookie陈醒,保存到OsApplication類中钉跷,并且持久化
  2. 啟動app的時候從持久化中獲取肚逸,保存到OsApplication類中,
  3. 調(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)登錄了呢?

  1. 把棧里所有activity都出棧府喳,重新new出新的帶登錄信息的activity再壓棧進(jìn)去
  2. 通過其他手段通知需要更新狀態(tài)的頁面:爺爺我登錄了蘑拯,你趕緊地更新頁面I昃健!

我覺得第二種比較劃算碎捺!而在安卓中,我們可以通過原生的廣播晋柱,第三方的EventBus來實(shí)現(xiàn)诵叁,而在flutter,我們可以考慮用插件event_bus: ^1.0. 1來實(shí)現(xiàn)碑诉。

它的實(shí)現(xiàn)方式和安卓版的類似:

  1. 寫event類
  2. 事件源發(fā)出event
  3. 接受源接受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)為要是有審美選丑比賽,我肯定可以奪得第一滔悉!

image.png

image.png

image.png

頁面拆解

一級頁面

一級頁面沒有什么難度,我們?nèi)匀挥卸喾N方案來實(shí)現(xiàn)它:

  1. listView
  2. CustomScrollView
  3. 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ù)性的勞動:

  1. 接接口
  2. 寫數(shù)據(jù)
  3. 畫UI

但是

但是flutter不止這么些可以玩的,動畫魁巩,2端交互谷遂,其其他他零零總總的,還有很多好玩的控件畴嘶,嗯...接下來繼續(xù)慢慢玩flutter集晚。

互勉

一起玩吧

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偷拔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子欺旧,更是在濱河造成了極大的恐慌辞友,老刑警劉巖顷啼,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钙蒙,死亡現(xiàn)場離奇詭異间驮,居然都是意外死亡竞帽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門疙渣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妄荔,“玉大人,你說我怎么就攤上這事哗伯∨窠牵” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嘉蕾。 經(jīng)常有香客問我荆针,道長,這世上最難降的妖魔是什么喉悴? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任箕肃,我火速辦了婚禮今魔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吟宦。我一直安慰自己涩维,他們只是感情好瓦阐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布睡蟋。 她就那樣靜靜地躺著,像睡著了一般该面。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上听诸,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天晌梨,我揣著相機(jī)與錄音须妻,去河邊找鬼。 笑死敛惊,一個胖子當(dāng)著我的面吹牛绰更,可吹牛的內(nèi)容都是我干的儡湾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尝丐!你這毒婦竟也來了爹袁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎根时,沒想到半個月后辰晕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體含友,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年宜咒,在試婚紗的時候發(fā)現(xiàn)自己被綠了把鉴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庭砍。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡怠缸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扳炬,到底是詐尸還是另有隱情搔体,我是刑警寧澤恨樟,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嫉柴,受9級特大地震影響厌杜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一竭恬、第九天 我趴在偏房一處隱蔽的房頂上張望袱箱。 院中可真熱鬧,春花似錦匙握、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽麦射。三九已至蛾娶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間潜秋,已是汗流浹背蛔琅。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留峻呛,地道東北人罗售。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓辜窑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寨躁。 傳聞我的和親對象是個殘疾皇子穆碎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容