參、不同類型List處理—Create lists with different types of items 參見: Create lists with different types of items
在List中,也有許多不同類型的變化可以作使用,包含以下幾個場景:
當List內有不同樣式的子元件
List內需要額外的空格空間
List內需要有多項類似的項目需呈現
倘若List內部需要有不同的子元件組成時,結構上,我們會遵照以下兩個步驟進行
建立不同型別物件之資料來源: 為每一種資料來源的類型項目做不同的Class、ListItem的定義
轉換元件清單: 將資料來源變為元件的方式呈現
一、建立不同型別物件的資料來源 1. 建立Class 在這段程式碼中,我們建立了三種Classes
ListItem
buildTitle(BuildContext context) :用於建立清單項目的標題部分,傳回一個顯示標題的Widget
buildSubtitle(BuildContext context) :用於建立清單項目的副標題部分,傳回一個顯示副標題的Widget
HeadingItem
final String heading :儲存標題的字串。
HeadingItem(this.heading) :建構函數,用於初始化HeadingItem類別,傳入標題作為參數。
buildTitle(BuildContext context) :實作ListItem 的 buildTitle,建構標題部分的Text元件,並使用headlineSmall樣式。
buildSubtitle(BuildContext context) :實作ListItem 的 buildSubtitle,這裡菜用傳回一個空的SizedBox小部件,表示沒有副標題。
MessageItem
final String sender :儲存發送者的名稱的字串。
final String body :儲存訊息的字串。
MessageItem(this.sender, this.body) :建構函數,用於初始化MessageItem類別的,傳入發送者名稱和訊息作為參數。
buildTitle(BuildContext context) :實作ListItem,建構標題Text,並顯示發送者名稱。
buildSubtitle(BuildContext context) :實作ListItem,建構副標題Text,並顯示訊息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 abstract class ListItem { Widget buildTitle(BuildContext context); Widget buildSubtitle(BuildContext context); } class HeadingItem implements ListItem { final String heading; HeadingItem(this.heading); @override Widget buildTitle(BuildContext context) { return Text( heading, style: Theme.of(context).textTheme.headlineSmall, ); } @override Widget buildSubtitle(BuildContext context) => const SizedBox.shrink(); } class MessageItem implements ListItem { final String sender; final String body; MessageItem(this.sender, this.body); @override Widget buildTitle(BuildContext context) => Text(sender); @override Widget buildSubtitle(BuildContext context) => Text(body); }
2. 建立ListItem 這段程式碼創建了一個 items 的列表,包含了1000個不同類型的列表項目。 用於模擬一個清單視圖的資料來源。 在產生這些清單項目時,程式碼使用了List.generate函數,index從0到999,並根據不同的index值來建立不同類型的清單項目。
我們以 (index % 6) 作為條件
1 2 3 4 5 6 final items = List<ListItem>.generate( 1000, (i) => i % 6 == 0 ? HeadingItem('Heading $i') : MessageItem('Sender $i', 'Message body $i'), );
我們可以使用 ListView.builder() 元件來將剛剛所呈現不同資料來源的項目轉為Widgets的方式。並且,ListView.builder()是動態產生的方式,不會一次將所有資料產生完畢,而會隨著資訊滾動的範圍呈現,助於提高效率!
1 2 3 4 5 6 7 8 9 10 ListView.builder( itemCount: items.length, //item項目長度 itemBuilder: (context, index) { //根據項目類型將不同型別的物件轉為Widgets final item = items[index]; return ListTile( title: item.buildTitle(context), subtitle: item.buildSubtitle(context), ); }, )
三、MixedList使用範例 我們將上述程式結合如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import 'package:flutter/material.dart'; void main() { runApp( MyApp( items: List<ListItem>.generate( 1000, (i) => i % 6 == 0 ? HeadingItem('Heading $i') : MessageItem('Sender $i', 'Message body $i'), ), ), ); } class MyApp extends StatelessWidget { final List<ListItem> items; const MyApp({super.key, required this.items}); @override Widget build(BuildContext context) { const title = 'Mixed List'; return MaterialApp( title: title, home: Scaffold( appBar: AppBar( title: const Text(title), ), body: ListView.builder( // Let the ListView know how many items it needs to build. itemCount: items.length, // Provide a builder function. This is where the magic happens. // Convert each item into a widget based on the type of item it is. itemBuilder: (context, index) { final item = items[index]; return ListTile( title: item.buildTitle(context), subtitle: item.buildSubtitle(context), ); }, ), ), ); } } /// The base class for the different types of items the list can contain. abstract class ListItem { /// The title line to show in a list item. Widget buildTitle(BuildContext context); /// The subtitle line, if any, to show in a list item. Widget buildSubtitle(BuildContext context); } /// A ListItem that contains data to display a heading. class HeadingItem implements ListItem { final String heading; HeadingItem(this.heading); @override Widget buildTitle(BuildContext context) { return Text( heading, style: Theme.of(context).textTheme.headlineSmall, ); } @override Widget buildSubtitle(BuildContext context) => const SizedBox.shrink(); } /// A ListItem that contains data to display a message. class MessageItem implements ListItem { final String sender; final String body; MessageItem(this.sender, this.body); @override Widget buildTitle(BuildContext context) => Text(sender); @override Widget buildSubtitle(BuildContext context) => Text(body); }
我們可以看到,透過上面的程式便可產出以每六個子訊息具有一個標題的Mixed List效果,並且藉由滑輪可以看到具有所有index 0~999的結果。這種方式適合具有相同型態大量資訊的列表作為使用,並可藉由不同定義的資料元素來加以組合、展現。
Index 0-9 Index 990-999