Flutter & OpenHarmony 社交App标签选择组件实现方案
本文介绍了如何在Flutter和OpenHarmony平台上实现标签选择组件。Flutter部分通过Tag和TagSelector组件实现多选标签功能,支持流式布局和选择数量限制。OpenHarmony ArkTS版本使用Flex组件实现类似功能,包含标签样式切换和选择逻辑。最后还展示了Flutter中可搜索标签选择器的实现方法,通过过滤机制支持标签搜索功能。这些组件适用于社交应用的内容分类和用户

前言
标签选择是社交应用中用于内容分类和用户兴趣标记的常用功能。一个优秀的标签选择组件需要支持多选、搜索过滤、自定义标签以及流式布局等功能。本文将详细讲解如何在Flutter和OpenHarmony平台上构建功能完善的标签选择组件。
Flutter标签选择实现
首先实现基础的标签组件。
class Tag extends StatelessWidget {
final String label;
final bool isSelected;
final VoidCallback onTap;
const Tag({
Key? key,
required this.label,
required this.isSelected,
required this.onTap,
}) : super(key: key);
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.grey[200],
borderRadius: BorderRadius.circular(20),
),
child: Text(
label,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontSize: 14,
),
),
),
);
}
}
Tag组件显示单个标签,根据选中状态切换背景色和文字颜色。圆角胶囊形状是标签的标准设计。
class TagSelector extends StatefulWidget {
final List<String> availableTags;
final List<String> selectedTags;
final Function(List<String>) onSelectionChanged;
final int? maxSelection;
const TagSelector({
Key? key,
required this.availableTags,
required this.selectedTags,
required this.onSelectionChanged,
this.maxSelection,
}) : super(key: key);
State<TagSelector> createState() => _TagSelectorState();
}
TagSelector组件管理标签选择状态。availableTags是可选标签列表,selectedTags是已选标签,maxSelection限制最大选择数量。
class _TagSelectorState extends State<TagSelector> {
late List<String> _selected;
void initState() {
super.initState();
_selected = List.from(widget.selectedTags);
}
Widget build(BuildContext context) {
return Wrap(
spacing: 8,
runSpacing: 8,
children: widget.availableTags.map((tag) {
final isSelected = _selected.contains(tag);
return Tag(
label: tag,
isSelected: isSelected,
onTap: () => _toggleTag(tag),
);
}).toList(),
);
}
Wrap组件实现流式布局,标签自动换行。spacing和runSpacing控制水平和垂直间距。map方法将标签数据转换为Tag组件列表。
void _toggleTag(String tag) {
setState(() {
if (_selected.contains(tag)) {
_selected.remove(tag);
} else {
if (widget.maxSelection == null ||
_selected.length < widget.maxSelection!) {
_selected.add(tag);
}
}
});
widget.onSelectionChanged(_selected);
}
}
_toggleTag方法处理标签切换逻辑。如果已选中则取消,未选中则添加(需检查是否超过最大数量)。状态变化后通过回调通知父组件。
OpenHarmony ArkTS实现
鸿蒙系统上的标签选择器实现。
@Component
struct TagSelector {
@Prop availableTags: string[] = []
@State selectedTags: string[] = []
maxSelection: number = 0
onSelectionChanged: (tags: string[]) => void = () => {}
build() {
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.availableTags, (tag: string) => {
this.TagItem(tag)
})
}
.width('100%')
}
Flex组件配合FlexWrap.Wrap实现流式布局。ForEach遍历标签列表生成标签项。
@Builder
TagItem(tag: string) {
Text(tag)
.fontSize(14)
.fontColor(this.isSelected(tag) ? Color.White : '#1C1C1E')
.backgroundColor(this.isSelected(tag) ? '#007AFF' : '#E5E5EA')
.borderRadius(20)
.padding({ left: 16, right: 16, top: 8, bottom: 8 })
.margin({ right: 8, bottom: 8 })
.onClick(() => this.toggleTag(tag))
}
isSelected(tag: string): boolean {
return this.selectedTags.includes(tag)
}
@Builder定义标签项构建方法。样式根据选中状态变化,选中显示蓝色背景白色文字,未选中显示灰色背景黑色文字。
toggleTag(tag: string) {
if (this.isSelected(tag)) {
this.selectedTags = this.selectedTags.filter(t => t !== tag)
} else {
if (this.maxSelection === 0 || this.selectedTags.length < this.maxSelection) {
this.selectedTags = [...this.selectedTags, tag]
}
}
this.onSelectionChanged(this.selectedTags)
}
}
toggleTag方法处理标签切换。使用filter移除标签,使用展开运算符添加标签。maxSelection为0表示不限制数量。
可搜索标签选择器
在Flutter中实现带搜索功能的标签选择器:
class SearchableTagSelector extends StatefulWidget {
final List<String> availableTags;
final Function(List<String>) onSelectionChanged;
const SearchableTagSelector({
Key? key,
required this.availableTags,
required this.onSelectionChanged,
}) : super(key: key);
State<SearchableTagSelector> createState() => _SearchableTagSelectorState();
}
class _SearchableTagSelectorState extends State<SearchableTagSelector> {
String _searchQuery = '';
List<String> _selected = [];
List<String> get _filteredTags {
if (_searchQuery.isEmpty) return widget.availableTags;
return widget.availableTags
.where((tag) => tag.toLowerCase().contains(_searchQuery.toLowerCase()))
.toList();
}
Widget build(BuildContext context) {
return Column(
children: [
TextField(
decoration: InputDecoration(
hintText: '搜索标签',
prefixIcon: Icon(Icons.search),
),
onChanged: (value) => setState(() => _searchQuery = value),
),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: _filteredTags.map((tag) {
return Tag(
label: tag,
isSelected: _selected.contains(tag),
onTap: () {
setState(() {
if (_selected.contains(tag)) {
_selected.remove(tag);
} else {
_selected.add(tag);
}
});
widget.onSelectionChanged(_selected);
},
);
}).toList(),
),
],
);
}
}
SearchableTagSelector在标签列表上方添加搜索框。_filteredTags根据搜索关键词过滤标签列表,实现实时搜索功能。这种设计在标签数量较多时非常有用。
自定义标签输入
在Flutter中实现自定义标签输入:
class CustomTagInput extends StatefulWidget {
final Function(String) onTagAdded;
const CustomTagInput({
Key? key,
required this.onTagAdded,
}) : super(key: key);
State<CustomTagInput> createState() => _CustomTagInputState();
}
class _CustomTagInputState extends State<CustomTagInput> {
final TextEditingController _controller = TextEditingController();
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: '输入自定义标签',
),
onSubmitted: _addTag,
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () => _addTag(_controller.text),
),
],
);
}
void _addTag(String tag) {
if (tag.trim().isNotEmpty) {
widget.onTagAdded(tag.trim());
_controller.clear();
}
}
}
CustomTagInput允许用户输入自定义标签。按回车或点击添加按钮将标签添加到列表。trim()去除首尾空格,确保标签有效。
总结
本文详细介绍了标签选择组件在Flutter和OpenHarmony两个平台上的实现。标签选择是社交应用内容分类的常用功能,需要支持多选和流式布局。两个平台都使用Wrap/Flex实现自动换行。在实际项目中,还可以扩展标签推荐、热门标签、标签分组等功能。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)