在上一篇文章Flutter系列:2.實現一個簡單的登陸界面經過一個簡單的登陸頁面帶入了Flutter中頁面構建的方式以及一些簡單控件的使用;在開發一個app前首要的任務每每是搭建app須要的基礎結構,好比底部菜單,路由導航,網絡請求以及一些經常使用的顏色、圖標、按鈕、toast組件等。git
本次的demo將實現一個簡單的app所需的基礎結構,實現一個簡單的app,基於底部TabBar的方式模塊切分,實現網絡層調用豆瓣api展現電影列表,任意界面登陸驗證,app以下圖。github
[GitHub源碼傳送]web
目前app設計中大部分app都是由底部TabBar菜單+頂部導航信息的方式構建的,在iOS開發中UITabBarController 和 UINavigationController 幾乎是APP的標配, 一樣在Flutter中基於Scaffold的構建方式也直接提供了appBar+body+bottomNavigationBar的方式來切分導航欄、內容和底部菜單,因此咱們只須要在首頁的Scaffold構造中傳入bottomNavigationBar便可。json
在Flutter中爲咱們提供了material design風格的BottomNavigationBar和iOS風格的CupertinoTabBar,咱們只須要選擇其一稍做封裝便可,本demo選擇CupertinoTabBar,並封裝到BottomNavWidget中,相關細節請看源碼。api
雖然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便可實現頁面的跳轉。app
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源碼傳送]