大多数时候,在开发时,您可能会发现自己用某种预定义的格式填充ListView。与其自己使用行、列和容器来创建这种布局,你可以使用Flutter中现成的小部件,即ListTile小部件来帮忙。
在本教程中,我将通过一些实际例子向您展示如何在Flutter应用程序中添加ListTile小组件。
什么是ListTile?
Flutter中的ListTile小组件是一个显示相关信息的UI元素。
它遵循 Material Design 的List规范。一个典型的ListTile被分为三个部分:开始、中心和结束。开始部分包含领先的小组件;中心部分包括标题和副标题;结束部分包含尾随的小组件。
它主要用于填充可滚动的视图,如ListView、Column和Row。例如,你可以使用ListTile来显示待办事项、电子邮件、导航选项等的列表。你也可以通过点击ListTile来接收点击事件。
如果你是一个视觉学习者,请看这个快速视频教程。
添加ListTile
这里是在ListView小组件内显示ListTile的最小代码:
ListView(
children: const [
ListTile(
leading: Icon(Icons.car_rental),
title: Text('Car'),
trailing: Icon(Icons.more_vert),
),
ListTile(
leading: Icon(Icons.flight),
title: Text('Flight'),
trailing: Icon(Icons.more_vert),
),
ListTile(
leading: Icon(Icons.train),
title: Text('Train'),
trailing: Icon(Icons.more_vert),
)
],
)
下面是代码是如何转化为设计的:
当你想使用ListTile来填充可能来自你的后台的长列表时,你可以在ListView.Builder里面包裹单个ListTile部件,并在ListTile里面显示数据,如下面的代码所示:
final List<String> items = List<String>.generate(10000, (i) => '$i');
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text(items[index]),
),
title: Text('Item ${items[index]}'),
subtitle: Text('Item description'),
trailing: Icon(Icons.more_vert),
);
},
)
输出:
ListTile变化
还有其他类型的ListTile,它们的存在允许你对其进行特定的操作。
这些是:
- CheckboxListTile
- RadioListTile
- 切换式列表(SwitchListTile
CheckboxListTile
CheckboxListTile小组件是ListTile和Checkbox小组件的组合。
你可以使用这个小组件来标记任何项目的完成--例如;待办事项。默认情况下,复选框显示在ListTile的右侧(对于从左到右的语言)。
下面是你如何添加CheckboxListTile小组件:
class Language {
String name;
bool isChecked;
Language(this.name, {this.isChecked = false});
}
// 1.
final List<Language> languages = [Language('English'), Language('French'), Language('German')];
ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
return CheckboxListTile(
// 2.
title: Text('${languages[index].name}'),
// 3.
value: languages[index].isChecked,
// 4.
onChanged: (bool? value) {
setState(() {
languages[index].isChecked = value!;
});
},
// 5.
secondary: const Icon(Icons.language),
);
},
)
代码块中的数字解释:
- 一个持有语言列表的变量
- 这显示了复选框的标签
- 这决定了是否要检查或取消检查项目
- 当你点击ListTile时,这个被调用
- 这充当了一个领先的图标
输出:
要交换次要的(领先的)部件和复选框,你可以使用controlAffinity
属性并将其设置为ListTileControlAffinity.leading
:
你也可以通过添加checkboxShape
参数并将其设置为RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))
,来改变复选框的形状:
RadioListTile
RadioListTile小组件是ListTile和RadioButton小组件的组合--这个小组件被用来从一个项目列表中选择一个单一的选项。
下面是你如何添加RadioListTile小组件:
// 1.
enum Gender { male, female }
// 2.
Gender? _gender = Gender.male;
ListView(
children: [
// 3.
RadioListTile<Gender>(
secondary: Icon(Icons.male),
controlAffinity: ListTileControlAffinity.trailing,
title: const Text('Male'),
// 4.
value: Gender.male,
// 5.
groupValue: _gender,
// 6.
onChanged: (Gender? value) {
setState(() {
_gender = value;
});
},
),
RadioListTile<Gender>(
secondary: Icon(Icons.female),
controlAffinity: ListTileControlAffinity.trailing,
title: const Text('Female'),
value: Gender.female,
groupValue: _gender,
onChanged: (Gender? value) {
setState(() {
_gender = value;
});
},
),
],
)
代码块中的数字解释:
- 一个枚举,用于保存RadioListTile的所有选择值
- 这样就可以使用枚举保存默认的选择
- 添加枚举类型的RadioListTile
- 将选择值分配给当前的列表瓦片。ListTile代表这个值
- 用来显示当前的选择值
- 当你切换单选按钮的时候,这个功能会被调用,并带有选择。
输出
SwitchListTile
SwitchListTile小组件是ListTile和Switch小组件的组合。
你可以使用这个小部件来构建UI交互,让用户切换应用程序的设置。
下面是你如何添加SwitchListTile小组件:
class Appliance {
String name;
bool isOn;
Appliance(this.name, {this.isOn = false});
}
// 1.
final List<Appliance> appliances = [
Appliance('TV'),
Appliance('Fan'),
Appliance('Refrigerator'),
];
ListView.builder(
itemCount: appliances.length,
itemBuilder: (context, index) {
return SwitchListTile(
// 2.
title: Text('${appliances[index].name}'),
// 3.
value: appliances[index].isOn,
// 4.
onChanged: (bool value) {
setState(() {
appliances[index].isOn = value;
});
},
);
},
)
代码块中的数字解释:
- 一个持有电器列表的变量
- 这显示ListTile的名称或标题
- 这决定了是否要打开或关闭开关
- 当你拨动开关时,这个被调用
输出
管理ListTile主题
主题是开发前端应用程序的一个重要方面。主题传达了你的品牌,而且--如果不仔细管理--你可能会浪费很多时间让所有的UI元素都遵循同样的规则。
假设你想改变ListTile的外观和感觉以配合你的设计。你真的有以下两种选择:
- 在widget层面改变主题
- 在应用程序层面上改变主题
在widget层面上改变主题
你可以通过直接修改ListTile的属性来改变它的外观,比如颜色、形状和大小。
下面是你如何改变ListTile的背景颜色、文本颜色和图标颜色:
return ListTile(
// 1.
tileColor: Colors.redAccent,
// 2.
textColor: Colors.white,
// 3.
iconColor: Colors.white,
);
代码块中的数字解释:
- 这将改变ListTile的背景颜色
- 改变出现在ListTile上的所有文本的颜色
- 这将改变出现在ListTile上的所有图标的颜色
在应用程序层面上改变主题
你可能想在所有的应用程序页面上改变ListTile小组件的视觉美感。你可以通过定义listTileTheme
,然后添加ListTileThemeData
小组件来做到这一点。
在ListTileThemeData
widget里面,你可以指定你想为你项目中的所有ListTile widget改变的所有属性。
这里是代码的例子:
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
listTileTheme: ListTileThemeData(
tileColor: Colors.redAccent,
textColor: Colors.white,
iconColor: Colors.white,
),
),
home: MyHomePage(),
);
第一种和第二种方法产生的结果都是一样的,如下图所示:
添加一个分隔符
添加一个分隔线可以帮助你清楚地区分项目,特别是当项目在中心部分用三条线显示时。
为了在ListTile项目之间添加分隔线,添加ListView
widget。在ListView
里面,添加ListTile.divideTiles
,带有瓦片属性和ListTiles的列表。
代码示例:
ListView(
children: ListTile.divideTiles(context: context, tiles: [
ListTile(
leading: Icon(Icons.car_rental),
title: Text('Car'),
),
ListTile(
leading: Icon(Icons.flight),
title: Text('Flight'),
),
ListTile(
leading: Icon(Icons.train),
title: Text('Train'),
),
]).toList(),
)
输出:
如果你使用ListView.Builder
,你可以用ListView.separated
来代替它,并添加返回分隔符的separatorBuilder
参数。
代码示例:
ListView.separated( // <-- SEE HERE
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text(items[index]),
),
title: Text('Item ${items[index]}'),
subtitle: Text('Item description'),
trailing: Icon(Icons.more_vert),
);
},
separatorBuilder: (context, index) { // <-- SEE HERE
return Divider();
},
)
输出:
添加扫一扫-撤消行为
扫除功能允许你用扫除的手势从列表中移除一个特定的ListTile。例如,你可以用这个功能从你的列表中删除一封邮件。
以下是步骤:
- 把你的
ListTile
widget包在Dismissiblewidget里面 - 在Dismissible小组件内,添加
onDismissed
参数并注册一个回调。在这里你可以写出从列表中删除项目的逻辑。
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Dismissible( // Step 1
key: Key(items[index]),
onDismissed: (direction) { // Step 2
setState(() {
items.removeAt(index);
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('${items[index]} dismissed')));
},
child: ListTile(
//visualDensity: VisualDensity(vertical: 4),
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text(items[index]),
),
title: Text('Item ${items[index]}'),
subtitle: Text('Item description'),
trailing: Icon(Icons.more_vert),
),
);
},
)
)
(注意:上面的代码只是把ListTile从UI中移除,你必须自己写商业逻辑来从数据库中移除项目)
输出:
改变ListTile的高度
有时你可能想在某种程度上调整ListTile的高度。ListTile小组件并不直接支持高度属性,因为它的尺寸是按照Material设计规范限制的。所以,为了增加或减少ListTile的高度,你可以使用visualDensity
属性。
将visualDensity
设置为正数将增加ListTile的高度,而负数将减少其高度。
(注意:你可以设置的最大和最小值是4和**-4**)
下面是代码的例子:
ListTile(
visualDensity: VisualDensity(vertical: 4), //<-- SEE HERE
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text(items[index]),
),
title: Text('Item ${items[index]}'),
subtitle: Text('Item description'),
trailing: Icon(Icons.more_vert),
);
输出:
自定义
你可以通过利用可用的属性来为ListTile添加各种自定义功能。例如,你可以改变它的颜色(在不同的状态下,如悬停、按下等),形状,在标题和其他元素之间添加空间,以及改变它的高度等。
你可以通过导航到它的定义看到它支持的所有属性。要看到所有的属性,只需右键单击,然后转到>****定义或使用。
结论
添加ListTile小组件可以帮助你提高应用程序的开发速度。它遵循材料规范,涵盖了你所需要的一切,以有意义地展示一个项目。
在本教程中,我们首先看了如何添加ListTile,它的类型,以及如何管理主题,并涵盖了一些场景,如添加分隔线和扫码功能,以及改变ListTile的高度,我希望你会发现这些对你建立下一个列表有帮助。