Flutter系列:3.APP基礎設施搭建

前言

在上一篇文章Flutter系列:2.實現一個簡單的登錄界面通過一個簡單的登錄頁面帶入了Flutter中頁面構建的方式以及一些簡單控件的使用;在開發一個app前首要的任務往往是搭建app需要的基礎結構,比如底部菜單,路由導航,網絡請求以及一些常用的顏色、圖標、按鈕、toast組件等。

本次的demo將實現一個簡單的app所需的基礎結構,實現一個簡單的app,基於底部TabBar的方式模塊切分,實現網絡層調用豆瓣api展示電影列表,任意界面登錄驗證,app如下圖。

[GitHub源碼傳送]

TabBar菜單

目前app設計中大部分app都是由底部TabBar菜單+頂部導航信息的方式構建的,在iOS開發中UITabBarController 和 UINavigationController 幾乎是APP的標配, 同樣在Flutter中基於Scaffold的構建方式也直接提供了appBar+body+bottomNavigationBar的方式來切分導航欄、內容和底部菜單,所以我們只需要在首頁的Scaffold構造中傳入bottomNavigationBar即可。

在Flutter中爲我們提供了material design風格的BottomNavigationBar和iOS風格的CupertinoTabBar,我們只需要選擇其一稍作封裝即可,本demo選擇CupertinoTabBar,並封裝到BottomNavWidget中,相關細節請看源碼。

body的切換

雖然Scaffold提供了appBar+body+bottomNavigationBar的組合,但是並沒有實現bottomNavigationBar點擊切換body頁面顯示功能,所以需要開發者自己去處理bottomNavigationBar的點擊回調來動態切換body中的內容。

不同的bottomNavigationBarItem對應着不同的顯示頁面,電影tabBar對應顯示電影列表頁面,發現tabBar對應顯示發現頁面... 他們都在body中,他們之間有着頻繁的切換但同時只能顯示一個頁面;基於此使用Stack佈局的方式來實現,每個頁面組成一個數組成爲Stack Widget的children並緩存避免重複創建,使用Offstage組件來包裝每個tab頁面,並將bottomNavigationBar當前選擇的index對應的頁面的offstage設置爲false, 這樣只有當前選擇的tab對應的頁面顯示在body中,而其他的界面並不會顯示也不會接收事件佔用空間。

路由導航

路由導航也是app常見的基礎功能,服務器通過下發路由信息可以實現動態的控制app的頁面跳轉,常用於動態頁面,push和web跳轉。

Flutter中的導航有點類似iOS的方式,都是通過棧的方式來管理路由頁面。Navigator就是Flutter中管理導航路線的Widget,注意Navigator管理的是頁面導航的路線,稱爲Route的東西而不是像iOS中直接管理的controller,而每個Route(CupertinoPageRoute)則可以通過builder來指定顯示的Widget,同時Navigator也提供了對Route 棧操作的方法,push和pop。

Navigator管理的對象是Route,Flutter提供了MaterialPageRoute和iOS風格的CupertinoPageRoute,MaterialPageRoute是根據手機平臺自動調整頁面的出現動畫,本Demo選用CupertinoPageRoute以從右到左的頁面出現動畫,然後指定其builder即可實現頁面的跳轉。

MaterialApp內置了一個頂層的導航器Navigator,routes屬性支持配置靜態的路由表,如果在routes中找不到對應的路由配置時則調用onGenerateRoute來支持動態的路由跳轉,它的定義如下:


所以我們需要通過一個函數來實現MaterialApp的onGenerateRoute就可以根據RouteSettings中的路由信息動態的生成頁面的Route,同時以Uri的方式來指定Route的名稱就可以實現動態傳參了,具體詳見Demo源碼中RouteManager類。

登錄註冊

登錄註冊頁面可能在app的任何頁面推出,同時可能不支持返回需要強制登錄的情況,在iOS中常常以present的方式出現,所以在Flutter中需要指定CupertinoPageRoute的fullscreenDialog屬性爲true即可

頁面的跳轉

在iOS的開發中基於UITabBarController 和 UINavigationController的構建方式中頁面跳轉是在UINavigationController內跳轉的,同時通過設置Controller的hidesBottomBarWhenPushed屬性支持動態的顯示和隱藏底部的TarBar, 每個TabBar對應的是一個獨立控制的UINavigationController,他們各自有自己路由的導航棧,在Flutter中提供的CupertinoTabScaffold通過爲每個TabBar指定顯示爲CupertinoTabView來實現了同樣的機制。

往往在開發中進入二級界面後底部的導航欄都是隱藏的,所以我們完全可以只使用MaterialApp內置的頂層Navigator來實現我們的導航控制,本Demo也是如此。

網絡請求

移動端的網絡環境是千變萬化的,所以app的網絡請求應該是一個異步的過程,不能阻塞主線程,本Demo是基於Dart的第三方Http網絡請求庫dio。

dio是一個強大的Dart Http請求庫,支持Restful API、FormData、攔截器、請求取消、Cookie管理、文件上傳/下載、超時等...

網絡層實現了通過dio請求到網絡數據然後反序列爲Model對象,dart中的json反序列化要比其他語言麻煩,藉助的是json_annotation這個庫。

從請求api到回調再到反序列爲Model對象這個過程都應該是一個異步的過程,所以他們返回的都是一個Futrure對象,使用Completer就可以很方便的生成一個Future, 然後在恰當的時候傳入數據或者錯誤來結束這個Future。

列表

列表的展示是基於FutureBuilder的方式,因爲其依賴api請求返回的future,當future的狀態變更時FutureBuilder會接收到最新的快照信息AsyncSnapshot,通過其當前快照來控制ListView或者CircularProgressIndicator的顯示。

其他

App開發中還有許多其他的基礎模塊,比如和原生通信組件(channel)、圖片組件、日誌組件、其他公共的彈窗、上下拉刷新組件等,本Demo還來不及一一實現,隨着學習的深入以後再慢慢總結吧,有不妥的地方還望指正。

Demo源碼地址:[GitHub源碼傳送]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章