Skip to content

[Flutter] 使用 ListView 元件建立清單介面

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 去學習,手機呈現的效果是會報錯的,直到現在我都還沒釐清我的疑惑——不過好在,我暫時測試出了以上這些使用方法,希望能給需要使用的人一些參考。

Tags:

Leave a Reply