Flutter實(shí)現(xiàn)圖文并茂的列表

界面布局分析
本篇要實(shí)現(xiàn)的列表如上圖所示。我們拿到界面設(shè)計(jì)稿之后,在 UI 開發(fā)工作第一件事就是考慮界面的元素和布局。以上面的界面為例,實(shí)際的界面元素包括了列表和列表元素,而列表元素是關(guān)鍵,列表元素包括了左邊的一張圖片,圖片右側(cè)的標(biāo)題和查看次數(shù)(帶前置圖標(biāo))。列表的元素的布局如下圖所示。

縱向上,列表元素的布局高度由圖片決定。圖標(biāo)和瀏覽數(shù)的高度固定,剩余的空間由標(biāo)題占據(jù)??紤]界面的美觀,標(biāo)題最大行數(shù)為2行,超出部分使用...替代。 橫向上,為保持圖片的固定長寬比,圖片寬度固定。寬度在圖片固定后,剩余的空間(除了間距留白外)即標(biāo)題的空間。 基于上述的描述,可以得到大致的布局:
- 整個(gè)列表元素使用一個(gè) Container 包裹,以便設(shè)置四周的外邊距;
- 橫向上,使用 Row 組件完成橫向布局。
- 右側(cè)區(qū)域使用 Column 組件完成縱向布局。
- 右側(cè)的瀏覽數(shù)的圖標(biāo)和文字也需要使用 Row 完成橫向布局。
- 為保持左側(cè)圖片和右側(cè)區(qū)域的間距,右側(cè)統(tǒng)一使用 Container 在外面包裹,以便控制間距。
ListView 簡介
ListView 用于生成列表,,通常使用 builder靜態(tài)方法構(gòu)建一個(gè)列表,其中關(guān)鍵的參數(shù)為:
- itemCount:列表元素的數(shù)量。
- itemBuilder:列表元素構(gòu)建函數(shù),通過指定元素的下標(biāo)返回對(duì)應(yīng)的列表元素組件。
如果要使用分隔組件的列表,也可以使用 ListView.seperate 方法構(gòu)建列表,這個(gè)方法多了一個(gè) seperateBuilder 參數(shù),用于返回列表元素間對(duì)應(yīng)的分隔組件。
因此,列表的關(guān)鍵是列表元素組件的實(shí)現(xiàn)。
編碼實(shí)現(xiàn)
我們還是基于上一個(gè)工程,在 dynamic.dart 中實(shí)現(xiàn)列表。在源代碼目錄新增兩個(gè)文件,分別是 dynamic_item.dart 用于構(gòu)建列表元素,dynamic_mock_data .dart用于模擬后臺(tái)接口數(shù)據(jù)。其中 dynamic_mock_data 的數(shù)據(jù)比較簡單,用一個(gè)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': '標(biāo)題${index + (page - 1) * size + 1}:這是一個(gè)列表標(biāo)題,最多兩行,多處部分將會(huì)被截取',
'imageUrl':
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3331308357,177638268&fm=26&gp=0.jpg',
'viewCount': 180,
};
});
}
}
其中 page 和 size 用于模擬分頁情況,方便后續(xù)實(shí)現(xiàn)上拉和下拉刷新。 注意這里使用了 List 的 generate 方法來構(gòu)建數(shù)組,該方法用于構(gòu)建指定大小的數(shù)組, 可以通過帶index輸入的回調(diào)函數(shù)構(gòu)建對(duì)飲 index 下標(biāo)的數(shù)組元素。
dynamic_item.dart的實(shí)現(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 幾個(gè)final 類型的成員屬性,使用 final 的約束是方便外部其他類可以直接訪問,但不可以做修改。如果這些屬性本身外部不可訪問,也可以定義為私有成員。
其次是使用構(gòu)造函數(shù)直接完成成員屬性的初始化,這是 Dart 語言的一種簡寫方法,只要傳參次序一致就可以不需要函數(shù)體自動(dòng)完成成員的初始化,通常會(huì)用在 final 修飾的成員屬性。
在 build 方法中完成了整個(gè)界面的構(gòu)建。其中注意這里使用了 Expanded 包裹右側(cè)區(qū)域,Expanded組件是表示橫向布局中,該組件將自動(dòng)占據(jù)剩余的空間。如果沒有這個(gè)包裹,會(huì)導(dǎo)致右側(cè)內(nèi)容過寬時(shí)無法顯示完全而報(bào)警。
圖片、標(biāo)題和瀏覽數(shù)均通過單獨(dú)的構(gòu)建組件方法獲取,這一方面是降低UI嵌套層級(jí),另一方面如果日后有同樣的組件,則可以抽離單獨(dú)的構(gòu)建方法提高復(fù)用性。下面對(duì)關(guān)鍵的幾個(gè)設(shè)置進(jìn)行解讀:
- crossAxisAlignment: CrossAxisAlignment.start:這個(gè)用于標(biāo)記Row行布局組件的元素在列方向上從起始位置開始對(duì)齊(即縱向上右側(cè)和圖片上沿對(duì)齊)。
- Container 的 margin:用于設(shè)置距離上下左右的間距,如果四個(gè)方向間距一致,就可以使用 EdgeInsets.all 方法設(shè)置。如果不一致就是要 EdgeInsets.fromLTRB 單獨(dú)設(shè)置四個(gè)方向的間距。
- 在瀏覽數(shù)組件中使用了一個(gè) SizedBox 組件,這個(gè)組件本身沒什么內(nèi)容,僅僅是為了將圖標(biāo)和瀏覽數(shù)字之間拉開一定的間距,提高美觀度。
用到的組件
除了 ListView 之外,本篇涉及到的組件如下:
- Text:文本組件,相當(dāng)于是 label。除了文字內(nèi)容外,可以使用 style 設(shè)置文字樣式。這里標(biāo)題使用了 maxLines 約束標(biāo)題最大2行,使用了 overflow 設(shè)置了文字溢出后處理方式。
- Image:圖片組件,這里使用了 Image.network 從網(wǎng)絡(luò)加載圖片,這個(gè) Image.network 是很初級(jí)的用法,后續(xù)會(huì)使用 cached_image_network 插件替換。
- Icon:圖標(biāo)組件,在 Flutter 中內(nèi)置了很多字體圖標(biāo),對(duì)于大部分場景都能夠滿足,圖標(biāo)可以使用 Icons 類定義的圖標(biāo)名稱來找到想要的圖標(biāo)。
- Row:行布局組件,其子組件 children 都是按先后順序從左到右在同一行依次排列。
- Column:列布局組件,其子組件 children 都是按從先后順序從上到下在同一列依次排列。
以上組件在本篇示例中都是基本應(yīng)用,更多設(shè)置可以在 IDE 中查看源碼或閱讀官方文檔了解。
結(jié)語:
本篇講述了使用 ListView 完成列表的構(gòu)建,重點(diǎn)講述了列表元素如何布局,具體的布局組件和實(shí)現(xiàn)方法。界面實(shí)現(xiàn)的關(guān)鍵工作實(shí)際是布局子元素的拆分。剩下的實(shí)現(xiàn)方式存在多種,看各人喜好。但是,需要注意避免過多嵌套導(dǎo)致代碼可讀性降低,以及提高 UI 組件的可復(fù)用性。
以上就是Flutter實(shí)現(xiàn)圖文并茂的列表的詳細(xì)內(nèi)容,更多關(guān)于Flutter實(shí)現(xiàn)圖文列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android代碼實(shí)現(xiàn)新年賀卡動(dòng)畫示例詳解
這篇文章主要為大家介紹了Android代碼實(shí)現(xiàn)新年賀卡動(dòng)畫示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Android 通過API獲取數(shù)據(jù)庫中的圖片文件方式
這篇文章主要介紹了Android 通過API獲取數(shù)據(jù)庫中的圖片文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03
android實(shí)現(xiàn)手機(jī)截屏并保存截圖功能
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)手機(jī)截屏并保存截圖功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
Flutter中數(shù)據(jù)存儲(chǔ)的四種方式小結(jié)
在 Flutter 中,存儲(chǔ)是指用于本地和遠(yuǎn)程存儲(chǔ)和管理數(shù)據(jù)的機(jī)制,本給大家介紹了Flutter中不同存儲(chǔ)選項(xiàng)的概述和示例,通過代碼示例講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下2023-11-11
android monkey自動(dòng)化測試改為java調(diào)用monkeyrunner Api
一般情況下我們使用android中的monkeyrunner進(jìn)行自動(dòng)化測試時(shí),使用的是python語言來寫測試腳本。不過,最近發(fā)現(xiàn)可以用java調(diào)用monkeyrunner Api,于是,就簡單研究了一下。這里做一些總結(jié)。希望有對(duì)在研究的午飯可以有所用處2012-11-11
Android編程實(shí)現(xiàn)獲取新浪天氣預(yù)報(bào)數(shù)據(jù)的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)獲取新浪天氣預(yù)報(bào)數(shù)據(jù)的方法,涉及Android基于新浪接口的調(diào)用及數(shù)據(jù)處理技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
android開發(fā)教程之獲取使用當(dāng)前api的應(yīng)用程序名稱
開發(fā)手機(jī)安全管家的時(shí)候,比如要打電話,或者照相需要知道是哪個(gè)應(yīng)用程序在調(diào)用,就可以在API接口中調(diào)用下面的代碼2014-02-02
Android平臺(tái)預(yù)置GMS包后關(guān)機(jī)鬧鐘失效問題及解決方法
這篇文章主要介紹了Android平臺(tái)預(yù)置GMS包后,關(guān)機(jī)鬧鐘失效,本文給大家分享問題原因及解決方法,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
將cantk runtime嵌入到現(xiàn)有的APP中的方法
今天小編就為大家分享一篇關(guān)于將cantk runtime嵌入到現(xiàn)有的APP中的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12

