Flutter實現(xiàn)圖文并茂的列表
界面布局分析
本篇要實現(xiàn)的列表如上圖所示。我們拿到界面設計稿之后,在 UI 開發(fā)工作第一件事就是考慮界面的元素和布局。以上面的界面為例,實際的界面元素包括了列表和列表元素,而列表元素是關鍵,列表元素包括了左邊的一張圖片,圖片右側的標題和查看次數(shù)(帶前置圖標)。列表的元素的布局如下圖所示。
縱向上,列表元素的布局高度由圖片決定。圖標和瀏覽數(shù)的高度固定,剩余的空間由標題占據(jù)??紤]界面的美觀,標題最大行數(shù)為2行,超出部分使用...替代。 橫向上,為保持圖片的固定長寬比,圖片寬度固定。寬度在圖片固定后,剩余的空間(除了間距留白外)即標題的空間。 基于上述的描述,可以得到大致的布局:
- 整個列表元素使用一個 Container 包裹,以便設置四周的外邊距;
- 橫向上,使用 Row 組件完成橫向布局。
- 右側區(qū)域使用 Column 組件完成縱向布局。
- 右側的瀏覽數(shù)的圖標和文字也需要使用 Row 完成橫向布局。
- 為保持左側圖片和右側區(qū)域的間距,右側統(tǒng)一使用 Container 在外面包裹,以便控制間距。
ListView 簡介
ListView 用于生成列表,,通常使用 builder靜態(tài)方法構建一個列表,其中關鍵的參數(shù)為:
- itemCount:列表元素的數(shù)量。
- itemBuilder:列表元素構建函數(shù),通過指定元素的下標返回對應的列表元素組件。
如果要使用分隔組件的列表,也可以使用 ListView.seperate 方法構建列表,這個方法多了一個 seperateBuilder 參數(shù),用于返回列表元素間對應的分隔組件。
因此,列表的關鍵是列表元素組件的實現(xiàn)。
編碼實現(xiàn)
我們還是基于上一個工程,在 dynamic.dart 中實現(xiàn)列表。在源代碼目錄新增兩個文件,分別是 dynamic_item.dart 用于構建列表元素,dynamic_mock_data .dart用于模擬后臺接口數(shù)據(jù)。其中 dynamic_mock_data 的數(shù)據(jù)比較簡單,用一個list 靜態(tài)方法返回分頁數(shù)據(jù),如下所示:
class DynamicMockData { static List<Map<String, Object>> list(int page, int size) { return List<Map<String, Object>>.generate(size, (index) { return { 'title': '標題${index + (page - 1) * size + 1}:這是一個列表標題,最多兩行,多處部分將會被截取', 'imageUrl': 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3331308357,177638268&fm=26&gp=0.jpg', 'viewCount': 180, }; }); } }
其中 page 和 size 用于模擬分頁情況,方便后續(xù)實現(xiàn)上拉和下拉刷新。 注意這里使用了 List 的 generate 方法來構建數(shù)組,該方法用于構建指定大小的數(shù)組, 可以通過帶index輸入的回調函數(shù)構建對飲 index 下標的數(shù)組元素。
dynamic_item.dart的實現(xiàn)代碼如下所示:
import 'package:flutter/material.dart'; class DynamicItem extends StatelessWidget { final String title; final String imageUrl; final int viewCount; static const double ITEM_HEIGHT = 100; static const double TITLE_HEIGHT = 80; static const double MARGIN_SIZE = 10; const DynamicItem(this.title, this.imageUrl, this.viewCount, {Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( margin: EdgeInsets.all(MARGIN_SIZE), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ _imageWrapper(this.imageUrl), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _titleWrapper(context, this.title), _viewCountWrapper(this.viewCount.toString()), ], ), ) ], ), ); } Widget _titleWrapper(BuildContext context, String text) { return Container( height: TITLE_HEIGHT, margin: EdgeInsets.fromLTRB(MARGIN_SIZE, 0, 0, 0), child: Text( this.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.headline6, ), ); } Widget _viewCountWrapper(String text) { return Container( margin: EdgeInsets.fromLTRB(MARGIN_SIZE, 0, 0, 0), height: ITEM_HEIGHT - TITLE_HEIGHT, child: Row(children: [ Icon( Icons.remove_red_eye_outlined, size: 14.0, color: Colors.grey, ), SizedBox(width: 5), Text( this.viewCount.toString(), style: TextStyle(color: Colors.grey, fontSize: 14.0), ), ]), ); } Widget _imageWrapper(String imageUrl) { return SizedBox( width: 150, height: ITEM_HEIGHT, child: Image.network(imageUrl), ); } }
首先定義了title、imageUrl和 viewCount 幾個final 類型的成員屬性,使用 final 的約束是方便外部其他類可以直接訪問,但不可以做修改。如果這些屬性本身外部不可訪問,也可以定義為私有成員。
其次是使用構造函數(shù)直接完成成員屬性的初始化,這是 Dart 語言的一種簡寫方法,只要傳參次序一致就可以不需要函數(shù)體自動完成成員的初始化,通常會用在 final 修飾的成員屬性。
在 build 方法中完成了整個界面的構建。其中注意這里使用了 Expanded 包裹右側區(qū)域,Expanded組件是表示橫向布局中,該組件將自動占據(jù)剩余的空間。如果沒有這個包裹,會導致右側內容過寬時無法顯示完全而報警。
圖片、標題和瀏覽數(shù)均通過單獨的構建組件方法獲取,這一方面是降低UI嵌套層級,另一方面如果日后有同樣的組件,則可以抽離單獨的構建方法提高復用性。下面對關鍵的幾個設置進行解讀:
- crossAxisAlignment: CrossAxisAlignment.start:這個用于標記Row行布局組件的元素在列方向上從起始位置開始對齊(即縱向上右側和圖片上沿對齊)。
- Container 的 margin:用于設置距離上下左右的間距,如果四個方向間距一致,就可以使用 EdgeInsets.all 方法設置。如果不一致就是要 EdgeInsets.fromLTRB 單獨設置四個方向的間距。
- 在瀏覽數(shù)組件中使用了一個 SizedBox 組件,這個組件本身沒什么內容,僅僅是為了將圖標和瀏覽數(shù)字之間拉開一定的間距,提高美觀度。
用到的組件
除了 ListView 之外,本篇涉及到的組件如下:
- Text:文本組件,相當于是 label。除了文字內容外,可以使用 style 設置文字樣式。這里標題使用了 maxLines 約束標題最大2行,使用了 overflow 設置了文字溢出后處理方式。
- Image:圖片組件,這里使用了 Image.network 從網絡加載圖片,這個 Image.network 是很初級的用法,后續(xù)會使用 cached_image_network 插件替換。
- Icon:圖標組件,在 Flutter 中內置了很多字體圖標,對于大部分場景都能夠滿足,圖標可以使用 Icons 類定義的圖標名稱來找到想要的圖標。
- Row:行布局組件,其子組件 children 都是按先后順序從左到右在同一行依次排列。
- Column:列布局組件,其子組件 children 都是按從先后順序從上到下在同一列依次排列。
以上組件在本篇示例中都是基本應用,更多設置可以在 IDE 中查看源碼或閱讀官方文檔了解。
結語:
本篇講述了使用 ListView 完成列表的構建,重點講述了列表元素如何布局,具體的布局組件和實現(xiàn)方法。界面實現(xiàn)的關鍵工作實際是布局子元素的拆分。剩下的實現(xiàn)方式存在多種,看各人喜好。但是,需要注意避免過多嵌套導致代碼可讀性降低,以及提高 UI 組件的可復用性。
以上就是Flutter實現(xiàn)圖文并茂的列表的詳細內容,更多關于Flutter實現(xiàn)圖文列表的資料請關注腳本之家其它相關文章!
相關文章
Android在layout xml中使用ViewStub完成動態(tài)加載問題
這篇文章主要介紹了Android在layout xml中使用ViewStub完成動態(tài)加載問題,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-08-08Android在WebView中調用系統(tǒng)下載的方法
這篇文章主要為大家詳細介紹了Android在WebView中調用系統(tǒng)下載的簡單使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05Android項目實戰(zhàn)之Glide 高斯模糊效果的實例代碼
這篇文章主要介紹了Android項目實戰(zhàn)之Glide 高斯模糊效果的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06Android中使用Notification實現(xiàn)狀態(tài)欄的通知
本文主要介紹了android利用Notification實現(xiàn)狀態(tài)欄的通知的示例代碼。具有很好的參考價值。下面跟著小編一起來看下吧2017-04-04音量控制鍵控制的音頻流(setVolumeControlStream)描述
當開發(fā)多媒體應用或者游戲應用的時候,需要使用音量控制鍵來設置程序的音量大小,在Android系統(tǒng)中有多種音頻流,感興趣的朋友可以了解下2013-01-01