Last Updated on 2021-05-17 by Clay
在使用 Flutter 開發 App 的過程中,我們時常會有需要建立一長串的『清單』(List) 這樣的需求,或者你習慣說『表單』、『列項』……諸如此類的名稱。
大致上,我所說的 List 有著以下這樣的樣貌:
這是開發 App 時經常會用到的資料表現型態。那麼今天,我打算來紀錄幾種不同的 ListView 使用方法,分別為:
- 靜態頁面
- 動態頁面
- ————-
- 分割效果
- 圖片效果
- 卡片效果
如果想參閱官方的教學,可以參考這裡: https://flutter.dev/docs/get-started/codelab
那麼以下,我就按順序紀錄以上這幾種 ListView 元件的使用方法吧!
事前準備
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: listview(), ), ); } }
首先,我們先創造程式的進入點, body 後方接著我們要展示的 listview() 程式。以下紀錄的程式都從這個進入點開始。
靜態頁面
靜態頁面顧名思義,便是不需動態調整 ListView 長度的頁面。通常多半用於顯示資料給使用者查看。
class listview extends StatelessWidget { @override Widget build(BuildContext context) { return ListView( children: <Widget>[ ListTile(title: Text('1')), ListTile(title: Text('2')), ListTile(title: Text('3')), ], ); } }
Output:
靜態頁面最為單純:我們只需要在 Widget 上直接設置 “ListView” 元件即可, ListView 底下的 Children 設定 Widget,將所需要顯示的資料以 ListTile 條列式寫下即可。
動態頁面
有些時候,我們所要顯示的資料非常龐大,靜態的頁面是無法把所有資料一次展現給使用者看的。這時候,我們就需要一個能夠『滾動』的頁面。
所幸,在 ListView 元件當中,我們可以輕易辦到這一點。我們直接將剛才寫好的 listview 進行修改:
class listview extends StatelessWidget { @override Widget build(BuildContext context) { final numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15']; return ListView.builder( itemCount: numbers.length, itemBuilder: (context, index){ return ListTile( title: Text(numbers[index]), ); } ); } }
Output:
還沒有顯示出來的部份,我們只需要往下滑動便可看到。
- numbers: 儲存所有我們要顯示的字串
- itemCount: ListView 元件顯示的長度,可以任意修改。若超過底下 numbers 長度的 index 會報錯
- itemBuilder: 設定 ListView 元件顯示的文字
當然,掌握 ListView.builder 便可產生無限的 ListView 元件:
class listview extends StatelessWidget{ @override Widget build(BuildContext context) { return ListView.builder( itemBuilder: (context, index) { return ListTile( title: Text('$index'), ); } ); } }
比如說像這樣,不設定 itemCount,這樣一來便會無限制地產生 Index 的清單。
分割效果
當然, ListView 元件有著各式各樣的展示效果,其中最常見的便是在每個條列資料之間插入『分隔線』。若是沒有這樣進行分隔的話,當使用者選取資料時可能會造成視覺上的疲勞。
class listview extends StatelessWidget{ @override Widget build(BuildContext context) { return ListView.separated( itemCount: 100, itemBuilder: (context, index) { return ListTile( title: Text('row $index'), ); }, separatorBuilder: (context, index){ return Divider(); }, ); } }
Output:
這裡我們不像剛才直接設定 ListView.builder,而是設置了 ListView.separated —— 別忘了最底下需要新增 separatorBuilder 返回的元件,這樣一來才能順利分隔顯示資料。
圖片效果
當然, ListView 不僅僅只能顯示文字,我們也能在文字旁加入 Icon 來使得界面更加生動活潑。
以下是個簡單的範例:
class listview extends StatelessWidget{ @override Widget build(BuildContext context) { return ListView( children: <Widget>[ ListTile( leading: Icon(Icons.people), title: Text('Name'), ), ListTile( leading: Icon(Icons.calendar_view_day), title: Text('Age'), ), ListTile( leading: Icon(Icons.grade), title: Text('Grade'), ) ], ); } }
Output:
我們需要做的僅僅只是在 ListTile 中加入 “leading: Icon(Icons.people)” 這樣程式碼,這是直接調用系統內建的 Icon 的方法。
順帶推薦一下,在 IDE 當中查看圖示的效果非常方便,甚至不用執行程式:
右側可以直接顯示出 Icon 的圖示,非常方便。(若是想要使用這個 IDE 進行 Flutter 的撰寫,可以參考我之前寫過的《Flutter 學習心得筆記 (0) 下載 Intellij IDEA》)
當然,我們也可以使用自己的圖片。首先創造一個 assets 的資料夾在根目錄底下(名稱可以自己取,我是直接叫 assets),然後在裡頭放入想要的圖片。
我的話,由於我目前正在進行的專案有魔物獵人的圖片,所以就直接拿來進行示範了。
原圖打開長這樣:
是魔物獵人當中『飾品』的圖示。
然後我們來到 pubspec.yaml 底下(通常也位於根目錄底下)增加該圖片的路徑:
添加好圖片路徑之後,回到程式,使用 AssetImage 將圖片讀取進來:
class listview extends StatelessWidget{ @override Widget build(BuildContext context) { return ListView( children: <Widget>[ ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/MHWI_0.png'), ), title: Text('Name'), ), ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/MHWI_0.png'), ), title: Text('Age'), ), ListTile( leading: CircleAvatar( backgroundImage: AssetImage('assets/MHWI_0.png'), ), title: Text('Grade'), ) ], ); } }
Output:
如此一來,我們就可以使用自己想要的 Icon 圖片了。
卡片效果
卡片效果其實應該跟分割效果放在一起講才對,無奈我最後才想到這件事。
卡片效果便是讓清單上的項目以『卡片』的方式呈現,同樣也是帶給使用者比較容易查看的體驗。
class listview extends StatelessWidget{ @override Widget build(BuildContext context) { final titles = ['Name', 'Age', 'Grade']; final icons = [Icons.people, Icons.calendar_view_day, Icons.grade]; return ListView.builder( itemCount: titles.length, itemBuilder: (context, index){ return Card( color: Colors.lightBlueAccent, child: ListTile( leading: Icon(icons[index]), title: Text(titles[index]), ) ); }, ); } }
Output:
使用方法也相當簡單:首先先將要顯示的『文字』以及『圖示』先儲存起來,然後在我們常用的 ViewTile 外面再包一層 Card 層。為了有好的展示效果,我將卡片的底色設置成了亮藍色。
以上,大致就是 Flutter 當中常用到的 ListView 的使用方法。其實我一開始按照官網的 Tutorial 去學習,手機呈現的效果是會報錯的,直到現在我都還沒釐清我的疑惑——不過好在,我暫時測試出了以上這些使用方法,希望能給需要使用的人一些參考。