天天看點

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

這一步不是很重要,提供一些假資料而已,不是重點嫌麻煩的可以跳過。

先介紹一個網址:點選

這個網址用來搭建我們需要的網絡資料,新增賬號非常簡單,這裡就不多說了。

注冊完成之後,建立一個倉庫,簡簡單單取個名字就夠了:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

之後點選進入倉庫,可以看到下圖:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

會預設生成以一個示例接口,可以看一看示例接口的生成規則。看不懂也沒關系,我們直接直接上手自己建立一個接口,如圖所示:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

點選右上角的編輯按鈕進入編輯模式,建立一個響應chatlist,類型為Array。然後生成chatlist的資料,imageUrl表示每條聊天資料的使用者頭像。其中使用者頭像的初始值裡面有一段@natural(20,99),這個是Mock.js代碼。這裡是相關介紹mockjs.com/

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

每條聊天資料,除了imageUrl還需要有使用者名name和消息的内容message。@cname用來生成随機的中文名,@cparagraph用來生成随機的中文段落來表示聊天内容。我們這裡隻是簡單的構造一下這個聊天清單所需要的資料,真正的聊天清單的資料肯定是不會這麼簡單的。。。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

編輯的差不多的時候,記得點選儲存,儲存之後點選紅圈中的圖示就可以擷取到資料

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

預設展示頁面改為<code>_currentIndex</code>改為0,建立<code>chat</code>目錄,将相關檔案放在這裡。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

加号按鈕這個東西,我們之前已經添加過類似的了,<code>appBar</code>的<code>actions</code>就是我們需要添加代碼的地方。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

如果我們按照這個思路寫下去的話,就需要自己再去實作一個彈出菜單的類。其實<code>flutter</code>提供了我們一些現成的類可以做到類似的效果。

<code>PopupMenuButton</code>類用來彈出一個菜單,必傳參數為<code>itemBuilder</code>,用來實作它需要展示的内容。<code>PopupMenuItem</code>就是用來展示内容的類。這裡有一個細節說一下,<code>PopupMenuButton</code>有一個<code>onSelected</code>屬性,這個屬性是個閉包,意思是選中某個<code>PopupMenuItem</code>的時候,會調用這個閉包。但是有一個前提就是每個<code>PopupMenuItem</code>的<code>value</code>必須不為null的時候,才會執行<code>onSelected</code>閉包,我在這裡卡了半天,網上找了半天資料也沒有明确講到這裡。其他就沒什麼好講的了,都比較簡單。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

還有一個小細節,如何設定<code>PopupMenuButton</code>的顔色,可以直接設定它的顔色

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

還可以設定APP的主題的<code>cardColor</code>,不過這個優先級沒有直接設定<code>PopupMenuButton</code>顔色高。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

這個網站可以搜尋<code>flutter</code>使用的包<code>packages</code>。我們使用<code>http</code>這個包來請求我們的網絡資料。這個包是<code>flutter</code>官方提供的。實際項目開發的時候可能并不會使用<code>http</code>這個包,大部分是使用<code>dio</code>來請求網絡資料。這裡隻介紹官方的http包如何使用。

首先作為一個開發者,有一個學習的氛圍跟一個交流圈子特别重要,這是一個我的iOS開發公衆号:程式設計大鑫,不管你是小白還是大牛都歡迎入駐 ,讓我們一起進步,共同發展!(群内會免費提供一些群主收藏的免費學習書籍資料以及整理好的幾百道面試題和答案文檔!)
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

粘貼完成之後需要更新一下,就是擷取一下包對應的代碼。可以通過上方的<code>Pub get</code>,也可以在終端中輸入<code>flutter packages get</code>

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

指令執行完之後,就可以使用這個包了。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

請求的發送寫在<code>initState</code>裡面。<code>getData()</code>後面跟了一個<code>async</code>表示的是異步執行。<code>async</code>需要搭配<code>await</code>使用,<code>await</code>後面跟着的是耗時的代碼。是以上面的程式會先列印來了,然後再輸出請求的狀态碼;

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

點選其他的頁面,再次回到目前頁面會發現<code>initState</code>方法重新走了一遍,這是因為我們還沒有儲存住狀态,後面會講到如何保持<code>Widget</code>的狀态。

首先介紹一下,在<code>flutter</code>中如何将請求傳回的<code>JSON</code>資料轉為<code>Map</code>,在我們<code>iOS</code>開發中是轉為字典,而flutter中沒有字典這個類型,對應的類型是<code>Map</code>。以及如果将<code>Map</code>轉為<code>JSON</code>。在<code>iOS</code>中我們知道會使用一個<code>NSJSONSerialization</code>的類用來處理<code>JSON</code>資料。同樣的,在<code>flutter</code>中也會有一個專門的類<code>JsonCodec</code>來處理。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

其中的<code>json</code>就是<code>JsonCodec</code>的執行個體。需要導入<code>'dart:convert'</code>頭檔案。<code>flutter中</code>還可以通過<code>is</code>來判斷是不是某個類型。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

除了紅框内的方法之外,其他沒什麼新鮮事物。紅框内的方法應該說是一個工廠方法,是設計模式的一種,用來初始化對象的。除了預設的初始化方法,還可以使用這個工廠方法來執行個體化一個Chat對象。模型建立好了之後就可以處理響應的資料了

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

這裡用到了Future,關于Future的講解可以看官方文檔dart.cn/tutorials/l…

很多時候我們會依賴一些異步資料來動态更新UI,比如在打開一個頁面時我們需要先從網際網路上擷取資料,在擷取資料的過程中我們顯示一個加載框,等擷取到資料時我們再渲染頁面;當然,通過<code>StatefulWidget</code>我們完全可以實作上述這些功能。但由于在實際開發中依賴異步資料更新UI的這種場景非常常見,是以<code>Flutter</code>專門提供了<code>FutureBuilder</code>來快速實作這種功能。<code>FutureBuilder</code>會依賴一個<code>future</code>,它會根據所依賴的<code>future</code>的狀态來動态建構自身。這個<code>future</code>我們剛剛已經準備好了。關于<code>FutureBuilder</code>的介紹就不詳細介紹了。 最後完整代碼如下:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

剛剛說了,我們可以使用<code>FutureBuilder</code>來快速實作展示異步網絡資料,也可以自己實作,現在我們自己實作一下。使用一個私有變量<code>_chatList</code>記錄請求下來的資料,再根據<code>_chatList</code>的值來展示不同的頁面。代碼如下:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

因為<code>getData</code>的傳回值是<code>Future</code>的原因,<code>getData()</code>後面可以跟<code>then</code>方法,還可以跟錯誤捕獲<code>catchError</code>,完成時的回調<code>whenComplete</code>,逾時設定<code>timeOut</code>等等,這種寫法挺有意思,一路點下去就完了...

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

在每次請求的時候,重置<code>_cancelConnect</code>的值。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

我們來回點選通訊錄頁面和聊天頁面,會發現每次點選進入目前的頁面,都會重新的載入,<code>initState()</code>會被重新調用。将通訊錄頁面滑動到底部,再次點選進入會發現又預設回到了頂部。為什麼會出現這樣的問題。正是因為我們的<code>Widget</code>的狀态沒有保持,每次展示都重新建立了。

<code>Dart</code>語言中有一個<code>Mixins</code>的概念:官方的解釋是這樣,可以給類<code>A Mixins</code>一個B,那麼A就擁有了B的屬性和方法。有點像OC的類擴充的意思。保持<code>Widget</code>的狀态就需要用到這個語言特性。一共有三個步驟:

1.<code>Mixins</code>類<code>AutomaticKeepAliveClientMixin</code>

重寫<code>wantKeepAlive</code>方法

調用父類<code>Builder</code>方法

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

同樣把通訊錄頁面也實作上面的步驟。然後再次來回點選發現還是沒有保持住狀态???這裡有一個最大的問題就是我們的根<code>Widget</code>都沒有保持住狀态,那還談什麼保持子<code>Widget</code>的狀态呢。。。

來到<code>rootPage.dart</code>檔案,我們會看到<code>body</code>裡面直接取了數組的某個元素作為根<code>Widget</code>展示。這樣是無法保持住狀态的,使用<code>PageView</code>才可以保持住狀态。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

使用PageView,代碼如下:

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

點選跳轉到其他頁面就可以直接通過<code>_pageController</code>來完成。使用了<code>PageView</code>之後會發現,不同的頁面之間可以直接通過手勢左右滑到就能切換了。這樣的效果我們一般是不需要的,可以設定直接關閉。如果需要的話,在滑動的方法裡面重新設定底部導覽列的正确位置也是沒有問題的。

八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态
八天讓iOS開發者上手Flutter!(六)準備網絡資料聊天頁面導覽列請求網絡資料使用FutureBuilder顯示界面不使用FutureBuilder的方式保持Widget的狀态

本篇文章就到這裡了,感謝觀看!