在这里插入图片描述

搜索功能是艺考学习应用中的核心功能之一,它能够帮助用户快速找到需要的题目。今天我们将详细介绍如何构建一个功能完善的搜索页面,包含实时搜索、高级筛选、搜索历史等功能,从UI设计、逻辑实现到性能优化全方位拆解。

搜索页面架构

搜索页面作为交互核心,状态管理是关键,因此选择StatefulWidget作为基础组件,核心设计要点如下:

  • 状态选择依据:搜索输入、结果、历史等信息均为动态变化,StatefulWidget可精准维护可变状态
  • 核心控制器:TextEditingController是监听输入框内容、实现实时搜索的基础
  • 代码解耦思路:将页面与状态分离,符合Flutter的组件设计规范
class SearchPage extends StatefulWidget {
  const SearchPage({Key? key}) : super(key: key);

  
  State<SearchPage> createState() => _SearchPageState();
}

状态类中需定义核心变量,变量设计遵循“职责单一”原则:

  • 基础状态变量:拆分搜索结果、历史、加载状态、筛选条件,便于单独维护
  • 常量复用:筛选类型、快捷搜索词设为固定常量,提升代码可维护性
class _SearchPageState extends State<SearchPage> {
  final TextEditingController _searchController = TextEditingController();
  List<Question> searchResults = [];
  List<String> searchHistory = [];
  bool isSearching = false;
  String selectedFilter = '全部';
}

搜索栏设计

搜索栏是用户接触搜索功能的首个入口,UI与交互设计需兼顾美观与实用:

  • 布局逻辑:Row+Expanded组合让输入框占满大部分宽度,筛选按钮固定右侧,布局更合理
  • 视觉优化:圆角边框+浅灰色填充色,贴合移动端用户的视觉习惯
  • 交互细节:清除按钮仅在输入有内容时显示,减少无效UI元素干扰
Widget _buildSearchBar() {
  return Container(
    padding: EdgeInsets.all(16.w),
    child: Row(
      children: [
        Expanded(
          child: TextField(
            controller: _searchController,
            decoration: InputDecoration(
              hintText: '搜索题目、关键词或分类...',
              prefixIcon: const Icon(Icons.search),

搜索栏的输入监听逻辑需保证即时性与合理性:

  • 实时搜索触发:onChanged监听输入,非空时执行搜索,为空时清空结果
  • 历史记录触发:仅在用户提交搜索时添加历史,避免输入过程中频繁记录
  • 清除交互:点击清除按钮清空输入框,同时重置搜索状态
              suffixIcon: _searchController.text.isNotEmpty
                  ? IconButton(icon: const Icon(Icons.clear),
                      onPressed: () {_searchController.clear();})
                  : null,
            ),
            onChanged: (value) {
              if (value.isNotEmpty) _performSearch(value);
              else {setState(() {isSearching = false;});}
            },
          ),
        ),
      ],
    ),
  );
}

搜索逻辑实现

搜索逻辑的核心是精准匹配与高效过滤,需兼顾全面性与准确性:

  • 模糊匹配维度:覆盖题目标题、分类、科目,统一转小写避免大小写漏查
  • 筛选条件结合:先匹配关键词,再过滤题目类型,双重校验保证结果精准
  • 数据来源:模拟数据可替换为真实接口,适配实际开发场景
void _performSearch(String query) {
  final allQuestions = MockData.getQuestions();
  setState(() {
    isSearching = true;
    searchResults = allQuestions.where((question) {
      final matchesQuery = question.title.toLowerCase().contains(query.toLowerCase()) ||
          question.category.toLowerCase().contains(query.toLowerCase());
      final matchesFilter = selectedFilter == '全部' || question.type == selectedFilter;
      return matchesQuery && matchesFilter;
    }).toList();
  });
}

性能优化:防抖处理

实时搜索易因输入过快触发频繁搜索,防抖技术可有效优化性能:

  • 防抖原理:通过Timer延迟执行搜索,输入间隔<300ms时取消前一次定时器
  • 延迟选择:300ms兼顾即时性与性能,避免卡顿或频繁请求
  • 内存管理:定时器及时取消,防止内存泄漏
Timer? _debounceTimer;
void _performSearch(String query) {
  _debounceTimer?.cancel();
  _debounceTimer = Timer(const Duration(milliseconds: 300), () {
    final allQuestions = MockData.getQuestions();
    setState(() {isSearching = true;});
  });
}

搜索结果展示

搜索结果展示直接影响用户体验,空状态与列表项设计需重点优化:

  • 空状态设计:图标+文字组合提示无结果,引导用户更换关键词
  • 视觉布局:空状态居中展示,符合用户视觉习惯,避免页面留白突兀
Widget _buildSearchResults() {
  if (searchResults.isEmpty) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.search_off, size: 80.w, color: Colors.grey[400]),
          SizedBox(height: 16.h),
          Text('未找到相关题目', style: TextStyle(fontSize: 18.sp)),
        ],
      ),
    );
  }

列表项采用卡片式设计,信息呈现需主次分明:

  • 视觉分隔:Card+ListTile组合,实现点击交互与视觉分隔的双重效果
  • 信息层级:标题突出,分类/科目作为副标题,关键信息一目了然
  • 页面跳转:点击项传递题目参数,实现详情页的无缝跳转
  return ListView.builder(
    itemCount: searchResults.length,
    itemBuilder: (context, index) {
      final question = searchResults[index];
      return Card(
        margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
        child: ListTile(
          title: Text(question.title, style: TextStyle(fontSize: 16.sp)),
          subtitle: Text('${question.category} - ${question.subject}'),
          onTap: () {Navigator.pushNamed(context, '/question_detail', arguments: question);},
        ),
      );
    },
  );
}

搜索历史管理

搜索历史可提升重复搜索效率,存储与展示逻辑需兼顾实用性:

  • 去重逻辑:添加前移除相同关键词,保证历史记录不重复
  • 数量限制:最多保留10条记录,避免历史过多导致页面杂乱
  • 持久化方案:实际开发中用SharedPreferences存储,重启应用仍可读取
void _loadSearchHistory() {
  // 模拟加载,实际替换为SharedPreferences读取
  searchHistory = ['色彩理论', '素描', '乐理'];
}

void _addToHistory(String term) {
  setState(() {
    searchHistory.remove(term);
    searchHistory.insert(0, term);
    if (searchHistory.length > 10) searchHistory.removeLast();
  });
}

高级筛选功能

高级筛选可精准缩小搜索范围,弹窗与交互设计需简洁易用:

  • 弹窗设计:AlertDialog设为最小高度,避免页面占比过大影响操作
  • 组件选择:ChoiceChip可视化展示筛选选项,选中状态清晰易识别
  • 即时反馈:选择后自动关闭弹窗并重新搜索,无需用户额外操作
void _showFilterDialog() {
  showDialog(
    context: context,
    builder: (context) {
      return AlertDialog(
        title: const Text('高级筛选'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text('题目类型'),
            const SizedBox(height: 8),

筛选选项的交互逻辑需保证状态同步与操作便捷:

  • 遍历复用:将筛选列表转为ChoiceChip,提升代码复用性
  • 状态更新:选中后同步筛选状态,立即触发重新搜索
  • 兜底设计:提供取消按钮,满足用户放弃筛选的需求
            Wrap(spacing: 8, children: filters.map((filter) {
              return ChoiceChip(
                label: Text(filter),
                selected: filter == selectedFilter,
                onSelected: (selected) {
                  setState(() {selectedFilter = filter;});
                  Navigator.pop(context);
                  if (_searchController.text.isNotEmpty) _performSearch(_searchController.text);
                },
              );
            }).toList()),
          ],
        ),
        actions: [TextButton(onPressed: () {Navigator.pop(context);}, child: const Text('取消'))],
      );
    },
  );
}

搜索技巧提示

搜索技巧提示可降低用户使用门槛,UI设计需醒目且不突兀:

  • 视觉区分:浅蓝背景+蓝色边框,与页面其他区域区分但不刺眼
  • 结构设计:标题+列表项组合,项目符号提升可读性
  • 内容适配:技巧贴合艺考题库场景,覆盖关键词、类型等核心搜索方式
Widget _buildSearchTips() {
  return Container(
    padding: EdgeInsets.all(16.w),
    decoration: BoxDecoration(
      color: Colors.blue[50],
      borderRadius: BorderRadius.circular(12.r),
      border: Border.all(color: Colors.blue[200]!),
    ),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('💡 搜索技巧', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
        SizedBox(height: 8.h),
        _buildTipItem('使用关键词如"色彩"、"素描"等'),
      ],
    ),
  );
}

技巧项样式需统一,适配不同屏幕尺寸:

  • 样式统一:文字大小、颜色保持一致,保证视觉连贯性
  • 布局适配:Row+Expanded组合,避免文字过长超出页面
Widget _buildTipItem(String tip) {
  return Padding(
    padding: EdgeInsets.only(top: 4.h),
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('• ', style: TextStyle(fontSize: 14.sp, color: Colors.blue[600])),
        Expanded(child: Text(tip, style: TextStyle(fontSize: 14.sp))),
      ],
    ),
  );
}

用户体验优化

为了提升用户体验,我们在搜索过程中添加了加载状态提示。当搜索结果为空时,显示友好的空状态界面,引导用户尝试其他搜索关键词。

数据持久化

搜索历史和用户偏好设置需要持久化存储。我们可以使用SharedPreferences来存储这些数据,确保用户下次使用时能够恢复之前的搜索状态。

通过以上实现,我们创建了一个功能完善、用户友好的搜索页面。这个页面不仅支持实时搜索和高级筛选,还提供了搜索历史和搜索技巧等功能,为用户提供了良好的搜索体验。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐