- 文章信息 - Author: 李俊才 (jcLee95)
Visit me at CSDN: https://jclee95.blog.csdn.net
My WebSite:http://thispage.tech/
Email: 291148484@163.com.
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/138425637
HuaWei:https://bbs.huaweicloud.com/blogs/426978
组件库地址:
- Pub.Dev:https://pub.dev/packages/widgets_easier
- GitHub:https://github.com/jacklee1995/widgets_easier
【介绍】:本文介绍Flutter的Widgets Easier组件库中:Widgets Easier组件库 - 标签(Tag)的使用方法。
](https://jclee95.blog.csdn.net/)
1. 概述 1.1 关于Widgets Easier
本库是一个 Flutter 组件库,旨在提供用于Flutter开发的组件,使得开发者能够更简单地构建出更丰富地界面效果。项目地址为:
-
https://github.com/jacklee1995/widgets_easier
-
https://pub.dev/packages/widgets_easier
在你的Flutter项目中,运行下面的命令:
flutter pub add widgets_easier
即可安装最新版本的 Widgets Easier 库。
2. 基本用法 2.1 语义类型通过Tag组件的type
参数可以使用一个语义性色彩。例如:
const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Tag('tag', type: SemanticEnum.primary),
Tag('tag', type: SemanticEnum.secondary),
Tag('tag', type: SemanticEnum.info),
Tag('tag', type: SemanticEnum.success),
Tag('tag', type: SemanticEnum.warning),
Tag('tag', type: SemanticEnum.danger),
Tag('tag', type: SemanticEnum.fatal),
],
),
2.2 样式主题
受启发与Element-plus,Tag有3个样式主题,plain
、light
和dark
,默认情况下为palin
,正如上一节所展示的那样。下面展示light
和dark
两个主题:
light
const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.primary),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.secondary),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.info),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.success),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.warning),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.danger),
Tag('tag', theme: TagThemeEnum.light, type: SemanticEnum.fatal),
],
),
dark
const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.primary),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.secondary),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.info),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.success),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.warning),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.danger),
Tag('tag', theme: TagThemeEnum.dark, type: SemanticEnum.fatal),
],
),
2.3 圆角
默认有一个大小为4的圆角,若要手动修改可以通过指定radius参数。radius参数接受一个double值。例如,设置radius为0则没有圆角:
Tag('radius: 0', radius: 0),
2.4 尺寸
枚举尺寸
例如:
Tag('SizeEnum.small', size: SizeEnum.small),
Tag('SizeEnum.defaultSize', size: SizeEnum.defaultSize),
Tag('SizeEnum.large', size: SizeEnum.large),
数值尺寸
通过height参数可以指定数值作为尺寸。height一经指定,则size失效。例如,指定高度为50:
Tag('hignt=50', height: 50),
收缩属性
通过指定shrink属性为flase,可以使一个标签尽可能占满一行,例如:
Tag('shrink: false', shrink: false)
2.5 可关闭标签
通过指定 closable: true,将展示一个关闭图标。例如:
const Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Tag('tag', closable: true, type: SemanticEnum.primary),
Tag('tag', closable: true, type: SemanticEnum.secondary),
Tag('tag', closable: true, type: SemanticEnum.info),
Tag('tag', closable: true, type: SemanticEnum.success),
Tag('tag', closable: true, type: SemanticEnum.warning),
Tag('tag', closable: true, type: SemanticEnum.danger),
Tag('tag', closable: true, type: SemanticEnum.fatal),
],
),
2.6 动态编辑标签示例
可以通过点击标签关闭按钮后触发的 onClose 事件来实现动态编辑标签。例如:
import 'package:flutter/material.dart';
import 'package:widgets_easier/widgets_easier.dart';
class DynamicTagsExample extends StatefulWidget {
const DynamicTagsExample({super.key});
State<DynamicTagsExample> createState() => _DynamicTagsExampleState();
}
class _DynamicTagsExampleState extends State<DynamicTagsExample> {
final List<String> _tags = ['Tag 1', 'Tag 2', 'Tag 3'];
final String _newTagButtonText = '+ 添加 Tag';
void _handleClose(int index) {
setState(() {
_tags.removeAt(index);
});
}
void _handleSubmitted(String value) {
if (value.isNotEmpty) {
setState(() {
_tags.add(value);
});
}
}
Widget build(BuildContext context) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: [
Text('$_tags'),
for (int index = 0; index < _tags.length; index++)
Tag(
key: UniqueKey(), // 重要
_tags[index],
type: SemanticEnum.primary,
theme: TagThemeEnum.light,
closable: true,
onClose: (_) {
_handleClose(index);
},
),
Tag(
_newTagButtonText,
type: SemanticEnum.danger,
editable: true,
restoreAfterSubmitted: true,
onSubmitted: _handleSubmitted,
),
],
);
}
}
效果如下:
另外,这个例子恰好是一定要指定key的例子,顺便说一下一种错误情况。
在没有使用 key
的情况下,Flutter 在构建组件树时,会根据组件的位置来匹配新旧组件。当删除一个 Tag 时,其后面的 Tag 会向前移动,占据被删除的 Tag 的位置。但是,Flutter 并不知道这种位置的变化,它仍然认为在原来的位置上的 Tag
与之前的 Tag
相同,导致视图没有正确更新。
这里,初始的 _tags 列表为 ['Tag 1', 'Tag 2', 'Tag 3']
,不断点击第一个Tag的close图标,看起来效果就成了这样:
在这个过程中:
-
Flutter 根据这个列表构建了三个
Tag
组件,它们在组件树中的位置分别为 0, 1, 2; -
现在,如果你删除了 ‘Tag 1’,
_tags
列表变为['Tag 2', 'Tag 3']
; -
Flutter 在更新组件树时,会比较新的组件列表与旧的组件列表:
-
在位置 0,它发现新的组件列表中有一个
Tag
组件,显示 ‘Tag 2’。但在旧的组件列表中,这个位置显示的是 ‘Tag 1’。因为 Flutter 使用位置来匹配组件,所以它认为这个Tag
组件没有变化,仍然显示 ‘Tag 1’; -
在位置 1,它发现新的组件列表中有一个
Tag
组件,显示 ‘Tag 3’。同样,因为位置匹配,Flutter 认为这个Tag
组件没有变化,仍然显示 ‘Tag 2’; -
在位置 2,它发现新的组件列表中没有
Tag
组件了,所以它会移除这个位置的Tag
组件。
-
-
最终,视图中显示的
Tag
组件是 ‘Tag 1’ 和 ‘Tag 2’,而不是 ‘Tag 2’ 和 ‘Tag 3’。
后面再次点击时类似。这就导致了在没有使用 key
的情况下,删除操作会导致视图与实际数据不一致。