Add a multi-criteria filtering feature (MultiFilterBar) to Flutter plugin views, supporting tags, keywords, date ranges, priority, checkboxes and other filter types. It replaces the traditional FilterDialog and provides a more intuitive two-level interactive UI. Suitable scenarios: (1) list views that require multi-dimensional filtering, (2) large datasets that need fast filtering, (3) applications that need to display filter conditions in real time.
为Flutter插件视图添加强大的多条件过滤功能,使用 SuperCupertinoNavigationWrapper 的 MultiFilterBar 组件。
# 基础用法 - 自动检测过滤需求
/add-multi-filter <view-file>
# 指定过滤条件类型
/add-multi-filter <view-file> --filters tags,priority,date,status
# 指定控制器变量名
/add-multi-filter <view-file> --controller _controller
Examples:
# 为待办事项插件添加过滤
/add-multi-filter lib/plugins/todo/views/todo_main_view.dart
# 为日记插件添加标签和日期过滤
/add-multi-filter lib/plugins/diary/views/diary_list_view.dart --filters tags,dateRange
# 自定义控制器名称
/add-multi-filter lib/plugins/activity/views/activity_list_view.dart --controller _activityController
<view-file>: 目标 Flutter 视图文件路径(包含 SuperCupertinoNavigationWrapper)--filters <types>: 过滤条件类型列表(逗号分隔)
tags, keyword, priority, date, dateRange, status, custom--controller <name>: 控制器变量名(默认:自动检测)读取目标文件并识别:
_plugin.taskController)在文件顶部添加导入:
import 'package:Memento/widgets/super_cupertino_navigation_wrapper/index.dart';
创建 _buildFilterItems() 方法,根据检测到的数据结构构建过滤条件:
/// 构建过滤条件列表
List<FilterItem> _buildFilterItems() {
// 获取动态数据
final availableTags = _controller.getAllTags();
return [
// 1. 标签多选过滤(如果有标签)
if (availableTags.isNotEmpty)
FilterItem(
id: 'tags',
title: 'plugin_tags'.tr,
type: FilterType.tagsMultiple,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildTagsFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
availableTags: availableTags,
);
},
getBadge: FilterBuilders.tagsBadge,
),
// 2. 优先级过滤(如果有优先级枚举)
FilterItem(
id: 'priority',
title: 'plugin_priority'.tr,
type: FilterType.custom,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildPriorityFilter<PriorityEnum>(
context: context,
currentValue: currentValue,
onChanged: onChanged,
priorityLabels: {
PriorityEnum.low: 'plugin_low'.tr,
PriorityEnum.medium: 'plugin_medium'.tr,
PriorityEnum.high: 'plugin_high'.tr,
},
priorityColors: const {
PriorityEnum.low: Colors.green,
PriorityEnum.medium: Colors.orange,
PriorityEnum.high: Colors.red,
},
);
},
getBadge: (value) => FilterBuilders.priorityBadge(
value,
{
PriorityEnum.low: 'plugin_low'.tr,
PriorityEnum.medium: 'plugin_medium'.tr,
PriorityEnum.high: 'plugin_high'.tr,
},
),
),
// 3. 日期范围过滤
FilterItem(
id: 'dateRange',
title: 'plugin_dateRange'.tr,
type: FilterType.dateRange,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildDateRangeFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
);
},
getBadge: FilterBuilders.dateRangeBadge,
),
// 4. 状态复选框过滤
FilterItem(
id: 'status',
title: 'plugin_status'.tr,
type: FilterType.checkbox,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildCheckboxFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
options: {
'option1': 'plugin_option1'.tr,
'option2': 'plugin_option2'.tr,
},
);
},
getBadge: FilterBuilders.checkboxBadge,
initialValue: const {
'option1': true,
'option2': true,
},
),
];
}
创建 _applyMultiFilters() 方法处理过滤变更:
/// 应用多条件过滤
void _applyMultiFilters(Map<String, dynamic> filters) {
// 构建过滤参数
final filterParams = <String, dynamic>{};
// 标签过滤
if (filters['tags'] != null && (filters['tags'] as List).isNotEmpty) {
filterParams['tags'] = filters['tags'];
}
// 优先级过滤
if (filters['priority'] != null) {
filterParams['priority'] = filters['priority'];
}
// 日期范围过滤
if (filters['dateRange'] != null) {
final range = filters['dateRange'] as DateTimeRange;
filterParams['startDate'] = range.start;
filterParams['endDate'] = range.end;
}
// 状态过滤
if (filters['status'] != null) {
final status = filters['status'] as Map<String, bool>;
filterParams['option1'] = status['option1'] ?? true;
filterParams['option2'] = status['option2'] ?? true;
}
// 应用过滤
if (filterParams.isEmpty) {
_controller.clearFilter();
} else {
_controller.applyFilter(filterParams);
}
setState(() {});
}
在 SuperCupertinoNavigationWrapper 中添加多条件过滤配置:
SuperCupertinoNavigationWrapper(
// ... 现有配置 ...
// 启用多条件过滤
enableMultiFilter: true,
multiFilterItems: _buildFilterItems(),
multiFilterBarHeight: 50,
onMultiFilterChanged: _applyMultiFilters,
// ... 其他配置 ...
)
如果存在旧的 FilterDialog:
_showFilterDialog() 方法// 移除这个按钮
IconButton(
icon: const Icon(Icons.filter_alt),
onPressed: _showFilterDialog, // ❌ 删除
),
在插件的国际化文件中添加必要的字符串:
中文 (zh):
'plugin_tags': '标签',
'plugin_priority': '优先级',
'plugin_low': '低',
'plugin_medium': '中',
'plugin_high': '高',
'plugin_dateRange': '日期范围',
'plugin_status': '状态',
'plugin_option1': '选项1',
'plugin_option2': '选项2',
英文 (en):
'plugin_tags': 'Tags',
'plugin_priority': 'Priority',
'plugin_low': 'Low',
'plugin_medium': 'Medium',
'plugin_high': 'High',
'plugin_dateRange': 'Date Range',
'plugin_status': 'Status',
'plugin_option1': 'Option 1',
'plugin_option2': 'Option 2',
| 类型 | FilterType | 构建器方法 | Badge方法 | 返回值 |
|------|-----------|-----------|----------|--------|
| 标签多选 | tagsMultiple | buildTagsFilter | tagsBadge | List<String> |
| 标签单选 | tagsSingle | buildTagFilter | tagBadge | String? |
| 关键词 | input | buildKeywordFilter | keywordBadge | String |
| 优先级 | custom | buildPriorityFilter<T> | priorityBadge | T? |
| 日期范围 | dateRange | buildDateRangeFilter | dateRangeBadge | DateTimeRange? |
| 单日期 | date | buildDateFilter | dateBadge | DateTime? |
| 复选框 | checkbox | buildCheckboxFilter | checkboxBadge | Map<String, bool> |
| 自定义 | custom | 自定义 widget | 自定义函数 | 任意类型 |
查找方法:
getAllTags(), getTags()List<String> 或 Set<String>查找枚举:
Prioritylow, medium, high查找方法:
applyFilter() 接受 startDate, endDate 参数DateTime 类型的字段查找方法:
applyFilter() 接受 showCompleted, showIncomplete 等布尔参数控制器需要实现以下方法:
class YourController extends ChangeNotifier {
// 必需:应用过滤
void applyFilter(Map<String, dynamic> filter) {
// 实现过滤逻辑
}
// 必需:清除过滤
void clearFilter() {
// 清除所有过滤条件
}
// 可选:获取标签列表
List<String> getAllTags() {
return _items.expand((item) => item.tags).toSet().toList();
}
// 可选:获取过滤后的数据
List<YourModel> get filteredItems {
return _applyFilterLogic(_items);
}
}
以下是一个完整的示例(基于 todo 插件):
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:Memento/widgets/super_cupertino_navigation_wrapper.dart';
import 'package:Memento/widgets/super_cupertino_navigation_wrapper/index.dart';
import 'package:Memento/plugins/todo/models/task.dart';
import 'package:Memento/plugins/todo/todo_plugin.dart';
class TodoListView extends StatefulWidget {
const TodoListView({super.key});
@override
State<TodoListView> createState() => _TodoListViewState();
}
class _TodoListViewState extends State<TodoListView> {
late TodoPlugin _plugin;
@override
void initState() {
super.initState();
_plugin = TodoPlugin.instance;
}
/// 构建过滤条件列表
List<FilterItem> _buildFilterItems() {
final availableTags = _plugin.taskController.getAllTags();
return [
// 标签多选
if (availableTags.isNotEmpty)
FilterItem(
id: 'tags',
title: 'todo_tags'.tr,
type: FilterType.tagsMultiple,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildTagsFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
availableTags: availableTags,
);
},
getBadge: FilterBuilders.tagsBadge,
),
// 优先级
FilterItem(
id: 'priority',
title: 'todo_priority'.tr,
type: FilterType.custom,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildPriorityFilter<TaskPriority>(
context: context,
currentValue: currentValue,
onChanged: onChanged,
priorityLabels: {
TaskPriority.low: 'todo_low'.tr,
TaskPriority.medium: 'todo_medium'.tr,
TaskPriority.high: 'todo_high'.tr,
},
priorityColors: const {
TaskPriority.low: Colors.green,
TaskPriority.medium: Colors.orange,
TaskPriority.high: Colors.red,
},
);
},
getBadge: (value) => FilterBuilders.priorityBadge(
value,
{
TaskPriority.low: 'todo_low'.tr,
TaskPriority.medium: 'todo_medium'.tr,
TaskPriority.high: 'todo_high'.tr,
},
),
),
// 日期范围
FilterItem(
id: 'dateRange',
title: 'todo_dateRange'.tr,
type: FilterType.dateRange,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildDateRangeFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
);
},
getBadge: FilterBuilders.dateRangeBadge,
),
// 完成状态
FilterItem(
id: 'status',
title: 'todo_status'.tr,
type: FilterType.checkbox,
builder: (context, currentValue, onChanged) {
return FilterBuilders.buildCheckboxFilter(
context: context,
currentValue: currentValue,
onChanged: onChanged,
options: {
'showCompleted': 'todo_showCompleted'.tr,
'showIncomplete': 'todo_showIncomplete'.tr,
},
);
},
getBadge: FilterBuilders.checkboxBadge,
initialValue: const {
'showCompleted': true,
'showIncomplete': true,
},
),
];
}
/// 应用多条件过滤
void _applyMultiFilters(Map<String, dynamic> filters) {
final filterParams = <String, dynamic>{};
if (filters['tags'] != null && (filters['tags'] as List).isNotEmpty) {
filterParams['tags'] = filters['tags'];
}
if (filters['priority'] != null) {
filterParams['priority'] = filters['priority'];
}
if (filters['dateRange'] != null) {
final range = filters['dateRange'] as DateTimeRange;
filterParams['startDate'] = range.start;
filterParams['endDate'] = range.end;
}
if (filters['status'] != null) {
final status = filters['status'] as Map<String, bool>;
filterParams['showCompleted'] = status['showCompleted'] ?? true;
filterParams['showIncomplete'] = status['showIncomplete'] ?? true;
}
if (filterParams.isEmpty) {
_plugin.taskController.clearFilter();
} else {
_plugin.taskController.applyFilter(filterParams);
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return SuperCupertinoNavigationWrapper(
title: Text('todo_tasks'.tr),
largeTitle: 'todo_tasks'.tr,
// 启用多条件过滤
enableMultiFilter: true,
multiFilterItems: _buildFilterItems(),
multiFilterBarHeight: 50,
onMultiFilterChanged: _applyMultiFilters,
body: AnimatedBuilder(
animation: _plugin.taskController,
builder: (context, _) {
return TaskListWidget(
tasks: _plugin.taskController.filteredTasks,
);
},
),
);
}
}
建议不超过 4-5 个过滤条件,过多会影响用户体验。
对于动态数据(如标签列表),使用条件渲染:
if (availableTags.isNotEmpty)
FilterItem(
id: 'tags',
// ...
),
为常用过滤条件设置合理的初始值:
FilterItem(
id: 'status',
// ...
initialValue: const {
'showCompleted': true,
'showIncomplete': true,
},
),
在 onMultiFilterChanged 中使用防抖处理(如果过滤操作很耗时):
Timer? _filterDebounce;
void _applyMultiFilters(Map<String, dynamic> filters) {
_filterDebounce?.cancel();
_filterDebounce = Timer(const Duration(milliseconds: 300), () {
// 执行过滤逻辑
});
}
所有用户可见的文本都应该使用国际化:
title: 'plugin_filterName'.tr,
完成后验证:
flutter analyze 无错误检查控制器的 applyFilter() 方法是否正确实现。
确保 getBadge 函数返回非空字符串。
检查 getAllTags() 方法是否正确返回数据。
确保导入了 Material 组件:
import 'package:flutter/material.dart';
flutter analyze 验证代码USAGE_EXAMPLE.md 获取更多示例Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer