## 新增功能 - 实时搜索:支持书名和作者的模糊搜索,300ms防抖优化 - Provider状态管理:使用ChangeNotifier模式管理搜索状态 - 搜索页面:完整的搜索UI,包括空状态、搜索中、无结果和结果列表 - 智能交互:一键清空搜索、焦点管理、状态同步 ## 技术实现 - SearchProvider:防抖搜索、状态管理、多字段匹配 - SearchPage:StatefulWidget管理、控制器协调、生命周期优化 - 状态同步:TextEditingController与Provider协调,避免循环更新 - 用户体验:即时反馈、智能清空、页面状态重置 ## 代码质量 - Flutter分析零警告 - 完整的代码注释和文档 - 内存安全:正确的资源清理 - 性能优化:防抖机制和精确UI重建 ## 文档完善 - Provider状态管理学习指南 - 搜索功能开发实战总结 - 顶部导航组件开发总结 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
159 lines
4.5 KiB
Dart
159 lines
4.5 KiB
Dart
import 'package:flutter/material.dart';
|
||
import '../pages/search_page.dart';
|
||
|
||
/// 应用顶部导航组件
|
||
///
|
||
/// 可复用的顶部导航栏组件,集成在搜索栏内的导入按钮。
|
||
/// 提供统一的搜索和文件导入功能,支持主题自适应。
|
||
class AppHeader extends StatelessWidget {
|
||
/// 标题文本(可选),某些页面可以显示标题而非搜索栏
|
||
final String? title;
|
||
|
||
/// 搜索按钮点击回调函数
|
||
final VoidCallback? onSearchPressed;
|
||
|
||
/// 导入按钮点击回调函数
|
||
final VoidCallback? onImportPressed;
|
||
|
||
/// 是否显示搜索栏(默认值为true)
|
||
final bool showSearchBar;
|
||
|
||
/// 搜索栏占位符文本
|
||
final String searchHint;
|
||
|
||
const AppHeader({
|
||
super.key,
|
||
this.title,
|
||
this.onSearchPressed,
|
||
this.onImportPressed,
|
||
this.showSearchBar = true,
|
||
this.searchHint = '搜索书名或内容...',
|
||
});
|
||
|
||
/// 构建组件的UI结构
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Container(
|
||
height: 60,
|
||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||
decoration: BoxDecoration(
|
||
color: Theme.of(context).colorScheme.surface,
|
||
border: Border(
|
||
bottom: BorderSide(
|
||
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
|
||
width: 1,
|
||
),
|
||
),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
// 标题区域(条件渲染)
|
||
if (title != null) ...[
|
||
Text(
|
||
title!,
|
||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||
fontWeight: FontWeight.w600,
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
],
|
||
|
||
// 搜索栏区域(占据剩余空间)
|
||
if (showSearchBar) ...[
|
||
Expanded(
|
||
child: _buildSearchBar(context),
|
||
),
|
||
]
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建搜索栏组件,包含搜索图标、占位符文本和导入按钮
|
||
Widget _buildSearchBar(BuildContext context) {
|
||
return Container(
|
||
height: 44,
|
||
decoration: BoxDecoration(
|
||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||
borderRadius: BorderRadius.circular(22),
|
||
border: Border.all(
|
||
color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
|
||
),
|
||
),
|
||
child: Material(
|
||
color: Colors.transparent,
|
||
child: InkWell(
|
||
borderRadius: BorderRadius.circular(22),
|
||
onTap: onSearchPressed ?? () => _navigateToSearchPage(context),
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
Icons.search,
|
||
size: 24,
|
||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: Text(
|
||
searchHint,
|
||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||
color: Theme.of(context)
|
||
.colorScheme
|
||
.onSurfaceVariant
|
||
.withOpacity(0.6),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
_buildImportButton(context),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
/// 构建导入按钮组件
|
||
Widget _buildImportButton(BuildContext context) {
|
||
return Container(
|
||
height: 32,
|
||
decoration: BoxDecoration(
|
||
color: Theme.of(context).colorScheme.primaryContainer,
|
||
borderRadius: BorderRadius.circular(16),
|
||
),
|
||
child: Material(
|
||
color: Colors.transparent,
|
||
child: InkWell(
|
||
borderRadius: BorderRadius.circular(16),
|
||
onTap: onImportPressed,
|
||
child: Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Text(
|
||
'导入',
|
||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
// 添加这个新方法
|
||
void _navigateToSearchPage(BuildContext context) {
|
||
Navigator.of(context).push(
|
||
MaterialPageRoute(
|
||
builder: (context) => const SearchPage(),
|
||
),
|
||
);
|
||
} |