feat:增加博客搜索功能

This commit is contained in:
2025-11-16 21:56:26 +08:00
parent 47b6fb9937
commit 61922cbcd8
7 changed files with 298 additions and 34 deletions

View File

@@ -1,5 +1,8 @@
import 'package:blog_app/apis/blog.dart';
import 'package:blog_app/layout/drawer.dart';
import 'package:blog_app/layout/menu.dart';
import 'package:blog_app/models/blog.dart';
import 'package:blog_app/widget/search.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
@@ -11,6 +14,12 @@ class _HomePageState extends State<HomePage> {
int _currentPageIndex = 0;
late PageController _pageController;
bool _isSearching = false;
final TextEditingController _searchController = TextEditingController();
final FocusNode _searchFocusNode = FocusNode();
List<BlogSearch> _searchResults = [];
String _searchQuery = '';
@override
void initState() {
super.initState();
@@ -20,53 +29,145 @@ class _HomePageState extends State<HomePage> {
@override
void dispose() {
_pageController.dispose();
_searchController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
void _startSearch() {
setState(() {
_isSearching = true;
});
Future.delayed(Duration(milliseconds: 100), () {
_searchFocusNode.requestFocus();
});
}
void _exitSearch() {
setState(() {
_isSearching = false;
_searchController.clear();
_searchResults.clear();
_searchQuery = '';
});
FocusScope.of(context).unfocus();
}
void _clearSearch() {
_searchController.clear();
setState(() {
_searchResults.clear();
_searchQuery = '';
});
}
void _onSearchTextChanged(String query) async {
setState(() {
_searchQuery = query;
});
if (query.isEmpty) {
setState(() {
_searchResults.clear();
});
return;
}
final result = await searchBlog(query);
setState(() {
_searchResults = result;
});
}
Widget _buildLeading() {
if (_isSearching) {
return IconButton(
icon: Icon(Icons.arrow_back, color: Colors.white),
onPressed: _exitSearch,
);
}
return Builder(
builder:
(context) => IconButton(
icon: Icon(Icons.menu, color: Colors.white),
onPressed: () => Scaffold.of(context).openDrawer(),
),
);
}
Widget _buildAppBarTitle() {
if (_isSearching) {
return buildSearchField(
controller: _searchController,
focusNode: _searchFocusNode,
onChanged: _onSearchTextChanged,
);
}
return Text(
pages[_currentPageIndex].title,
style: TextStyle(color: Colors.white),
);
}
List<Widget> _buildAppBarActions() {
if (_isSearching) {
return [
if (_searchController.text.isNotEmpty)
IconButton(
icon: Icon(Icons.clear, color: Colors.white),
onPressed: _clearSearch,
),
];
} else {
return [
IconButton(
icon: Icon(Icons.search, color: Colors.white),
onPressed: _startSearch,
),
];
}
}
Widget _buildPageView() {
return _isSearching ? _buildSearchResults() : _buildNormalPageView();
}
Widget _buildNormalPageView() {
return PageView(
controller: _pageController,
onPageChanged: (index) {
setState(() {
_currentPageIndex = index;
if (_isSearching) {
_exitSearch();
}
});
},
children: pageWidgets,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
pages[_currentPageIndex].title,
style: TextStyle(color: Colors.white),
),
backgroundColor: Theme.of(context).colorScheme.primary,
elevation: 0,
leading: Builder(
builder:
(context) => IconButton(
icon: Icon(Icons.menu, color: Colors.white),
onPressed: () => Scaffold.of(context).openDrawer(),
),
),
actions: [
IconButton(
icon: Icon(Icons.search, color: Colors.white),
onPressed: () {},
),
],
),
drawer: _buildDrawer(),
body: Padding(padding: EdgeInsets.all(10), child: _buildPageView()),
);
Widget _buildSearchResults() {
if (_searchQuery.isEmpty) {
return buildSearchQueryEmpty();
}
if (_searchResults.isEmpty) {
return buildSearchResultEmpty(_searchQuery);
}
return buildSearchResultList(context, _searchResults);
}
void onTapDrawerItem(int index) {
setState(() {
_currentPageIndex = index;
if (_isSearching) {
_exitSearch();
}
});
_pageController.animateToPage(
index,
@@ -99,13 +200,26 @@ class _HomePageState extends State<HomePage> {
color: Colors.white,
child: Column(
children: [
// 抽屉头部
buildDrawerHeader(context),
// 菜单项列表
Expanded(child: _buildDrawerBody()),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: _buildAppBarTitle(),
backgroundColor: Theme.of(context).colorScheme.primary,
elevation: 0,
leading: _buildLeading(),
actions: _buildAppBarActions(),
),
drawer: _buildDrawer(),
body: Padding(padding: EdgeInsets.all(10), child: _buildPageView()),
);
}
}

View File

@@ -38,10 +38,10 @@ class TimelinePageState extends State<TimelinePage> {
return Indicator.dot(size: 12.0, color: colors.primary);
},
contentsBuilder: (context, index) {
return buildBlogListItem(
context,
provider.blogList[index],
index + 1,
final blog = provider.blogList[index];
return InkWell(
onTap: () => navigatorToBlogDetail(context, blog.id),
child: buildBlogListItem(context, blog, index + 1),
);
},
),