feat:增加博客分类模块
This commit is contained in:
155
lib/pages/blog_detail_page.dart
Normal file
155
lib/pages/blog_detail_page.dart
Normal file
@@ -0,0 +1,155 @@
|
||||
import 'package:blog_app/apis/blog.dart';
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:markdown_widget/config/toc.dart';
|
||||
import 'package:markdown_widget/widget/markdown.dart';
|
||||
|
||||
class BlogDetailPage extends StatefulWidget {
|
||||
final int blogId;
|
||||
|
||||
const BlogDetailPage({super.key, required this.blogId});
|
||||
|
||||
@override
|
||||
State<BlogDetailPage> createState() => _BlogDetailPageState();
|
||||
}
|
||||
|
||||
class _BlogDetailPageState extends State<BlogDetailPage> {
|
||||
final tocController = TocController();
|
||||
bool _showToc = false;
|
||||
late Future<Blog> _blogDetail;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_blogDetail = _loadBlogDetail();
|
||||
}
|
||||
|
||||
Future<Blog> _loadBlogDetail() async {
|
||||
try {
|
||||
return await queryBlogByIdApi(widget.blogId);
|
||||
} catch (e) {
|
||||
throw Exception('获取博客详情失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildBlogTitle(String title) {
|
||||
return Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTocPanel() => Visibility(
|
||||
visible: _showToc,
|
||||
child: Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
width: 250,
|
||||
height: 400,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withAlpha(50),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
border: Border.all(color: Colors.grey[300]!),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text(
|
||||
'目录',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TocWidget(
|
||||
controller: tocController,
|
||||
tocTextStyle: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildMarkdown(String data) =>
|
||||
MarkdownWidget(data: data, tocController: tocController);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('博客详情')),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: FutureBuilder<Blog>(
|
||||
future: _blogDetail,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [Text('加载失败: ${snapshot.error}')],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!snapshot.hasData) {
|
||||
return Center(child: Text('暂无数据'));
|
||||
}
|
||||
|
||||
final blogDetail = snapshot.data!;
|
||||
return _buildBlogDetailContent(context, blogDetail);
|
||||
},
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => setState(() => _showToc = !_showToc),
|
||||
mini: true,
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
child: Icon(_showToc ? Icons.close : Icons.list, color: Colors.white),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogDetailContent(BuildContext context, Blog blogDetail) {
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
_buildBlogTitle(blogDetail.title),
|
||||
SizedBox(height: 10),
|
||||
Expanded(child: _buildMarkdown(blogDetail.content!)),
|
||||
],
|
||||
),
|
||||
_buildTocPanel(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
139
lib/pages/blog_list_page.dart
Normal file
139
lib/pages/blog_list_page.dart
Normal file
@@ -0,0 +1,139 @@
|
||||
import 'package:blog_app/apis/blog.dart';
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/widget/blog.dart';
|
||||
import 'package:blog_app/widget/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BlogListPage extends StatefulWidget {
|
||||
final String category;
|
||||
|
||||
const BlogListPage({super.key, required this.category});
|
||||
|
||||
@override
|
||||
State<BlogListPage> createState() => _BlogListPageState();
|
||||
}
|
||||
|
||||
class _BlogListPageState extends State<BlogListPage> {
|
||||
late List<Blog> blogs = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadBlogList();
|
||||
}
|
||||
|
||||
Future<void> _loadBlogList() async {
|
||||
try {
|
||||
final result = await queryBlogByConditionApi(widget.category, null, null);
|
||||
setState(() {
|
||||
blogs = result;
|
||||
});
|
||||
} catch (e) {
|
||||
throw Exception('获取博客列表失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildTitle() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
'博客列表',
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
||||
),
|
||||
Text(
|
||||
'共 ${blogs.length} 篇',
|
||||
style: TextStyle(color: Colors.grey.shade600, fontSize: 14),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogItem(BuildContext context, Blog blog, int index) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return buildCard(
|
||||
context: context,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 25,
|
||||
child: Text(
|
||||
index.toString(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colors.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// 发布时间
|
||||
SizedBox(
|
||||
width: 150,
|
||||
child: Text(
|
||||
blog.createTime,
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
|
||||
),
|
||||
),
|
||||
|
||||
// 标题
|
||||
Expanded(
|
||||
child: Text(
|
||||
blog.title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colors.primary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlogList() {
|
||||
return ListView.builder(
|
||||
itemCount: blogs.length,
|
||||
itemBuilder: (context, index) {
|
||||
final blog = blogs[index];
|
||||
return InkWell(
|
||||
onTap: () => navigatorToBlogDetail(context, blog.id),
|
||||
child: _buildBlogItem(context, blog, index + 1),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('博客详情')),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
widget.category,
|
||||
style: TextStyle(fontSize: 20, color: colors.primary),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildTitle(),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(child: blogs.isEmpty ? buildEmpty() : _buildBlogList()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:blog_app/apis/blog.dart';
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/widget/easy_refresh.dart';
|
||||
import 'package:blog_app/widget/blog.dart';
|
||||
import 'package:easy_refresh/easy_refresh.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BlogPage extends StatefulWidget {
|
||||
@@ -13,26 +15,129 @@ class BlogPage extends StatefulWidget {
|
||||
class _BlogPageState extends State<BlogPage> {
|
||||
late List<Blog> blogList = [];
|
||||
|
||||
int _currentPage = 1;
|
||||
final int _pageSize = 5;
|
||||
bool _hasMore = true;
|
||||
bool _showScrollToTop = false;
|
||||
|
||||
final EasyRefreshController _freshController = EasyRefreshController(
|
||||
controlFinishRefresh: true,
|
||||
controlFinishLoad: true,
|
||||
);
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始加载数据
|
||||
_loadData();
|
||||
_loadData(isRefresh: true);
|
||||
_scrollController.addListener(_onScroll);
|
||||
}
|
||||
|
||||
Future<void> _loadData() async {
|
||||
final result = await queryBlogByPageApi(1, 10);
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.removeListener(_onScroll);
|
||||
_freshController.dispose();
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
setState(() {
|
||||
blogList = result.records;
|
||||
});
|
||||
Future<void> _loadData({required bool isRefresh}) async {
|
||||
try {
|
||||
// 如果是刷新,重置页码
|
||||
if (isRefresh) {
|
||||
_currentPage = 1;
|
||||
}
|
||||
|
||||
final result = await queryBlogByPageApi(_currentPage, _pageSize);
|
||||
|
||||
setState(() {
|
||||
if (isRefresh) {
|
||||
// 刷新时直接替换数据
|
||||
blogList = result.records;
|
||||
} else {
|
||||
// 加载更多时追加数据
|
||||
blogList.addAll(result.records);
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
_hasMore = result.current < result.pages;
|
||||
// 如果有更多数据,准备加载下一页
|
||||
if (_hasMore) {
|
||||
_currentPage++;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// 处理错误
|
||||
debugPrint('加载数据失败: $e');
|
||||
} finally {
|
||||
_freshController.finishRefresh();
|
||||
_freshController.resetFooter();
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉刷新
|
||||
Future<void> _onRefresh() async {
|
||||
await _loadData(isRefresh: true);
|
||||
}
|
||||
|
||||
// 上拉加载
|
||||
Future<void> _onLoad() async {
|
||||
if (_hasMore) {
|
||||
await _loadData(isRefresh: false);
|
||||
_freshController.finishLoad(IndicatorResult.success);
|
||||
} else {
|
||||
_freshController.finishLoad(IndicatorResult.noMore);
|
||||
}
|
||||
}
|
||||
|
||||
void _onScroll() {
|
||||
// 当滚动距离超过300时显示返回顶部按钮
|
||||
if (_scrollController.offset > 300) {
|
||||
if (!_showScrollToTop) {
|
||||
setState(() {
|
||||
_showScrollToTop = true;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (_showScrollToTop) {
|
||||
setState(() {
|
||||
_showScrollToTop = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动到顶部
|
||||
void _scrollToTop() => scrollToTopAnimateTo(_scrollController);
|
||||
|
||||
Widget buildBlogList() {
|
||||
return ListView.builder(
|
||||
controller: _scrollController,
|
||||
itemCount: blogList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final blog = blogList[index];
|
||||
return InkWell(
|
||||
onTap: () => navigatorToBlogDetail(context, blog.id),
|
||||
child: BlogCard(blog: blogList[index]),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
itemCount: blogList.length,
|
||||
itemBuilder: (context, index) => BlogCard(blog: blogList[index]),
|
||||
return Stack(
|
||||
children: [
|
||||
buildEasyRefresh(
|
||||
freshController: _freshController,
|
||||
onRefresh: _onRefresh,
|
||||
onLoad: _onLoad,
|
||||
body: buildBlogList(),
|
||||
),
|
||||
if (_showScrollToTop)
|
||||
buildScrollToTop(context: context, scrollToTop: _scrollToTop),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
154
lib/pages/category_page.dart
Normal file
154
lib/pages/category_page.dart
Normal file
@@ -0,0 +1,154 @@
|
||||
import 'package:blog_app/apis/blog.dart';
|
||||
import 'package:blog_app/models/blog.dart';
|
||||
import 'package:blog_app/pages/blog_list_page.dart';
|
||||
import 'package:blog_app/widget/common.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CategoryPage extends StatefulWidget {
|
||||
const CategoryPage({super.key});
|
||||
|
||||
@override
|
||||
State<CategoryPage> createState() => _CategoryPageState();
|
||||
}
|
||||
|
||||
class _CategoryPageState extends State<CategoryPage> {
|
||||
late List<BlogCategory> categories = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadBlogCategory();
|
||||
}
|
||||
|
||||
Future<void> _loadBlogCategory() async {
|
||||
try {
|
||||
final result = await queryBlogCategoryApi();
|
||||
setState(() {
|
||||
categories = result;
|
||||
});
|
||||
} catch (e) {
|
||||
throw Exception('获取博客分类失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildTitle() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'共 ${categories.length} 个分类',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildTitle(),
|
||||
SizedBox(height: 10),
|
||||
// 分类列表
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: categories.length,
|
||||
itemBuilder: (context, index) {
|
||||
final category = categories[index];
|
||||
return _buildCategoryCard(context, category);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCategoryCard(BuildContext context, BlogCategory category) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
|
||||
return buildCard(
|
||||
context: context,
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 50,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: colors.primary.withAlpha(50),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(Icons.folder, color: colors.primary, size: 28),
|
||||
),
|
||||
title: Text(
|
||||
category.name,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
subtitle: Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: Text(
|
||||
'${category.count} 篇博客',
|
||||
style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
|
||||
),
|
||||
),
|
||||
trailing: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: colors.primary.withAlpha(50),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Text(
|
||||
category.count.toString(),
|
||||
style: TextStyle(
|
||||
color: colors.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () => _navigateToBlogList(context, category),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _navigateToBlogList(BuildContext context, BlogCategory category) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BlogListPage(category: category.name),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCategoryDetail(BuildContext context, BlogCategory category) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text(category.name),
|
||||
content: Text('该分类下有 ${category.count} 篇博客'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('关闭'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
// 这里可以添加跳转到该分类博客列表的逻辑
|
||||
},
|
||||
child: const Text('查看博客'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:blog_app/layout/drawer.dart';
|
||||
import 'package:blog_app/layout/menu.dart';
|
||||
import 'package:blog_app/pages/about_page.dart';
|
||||
import 'package:blog_app/pages/blog_page.dart';
|
||||
import 'package:blog_app/pages/message_page.dart';
|
||||
import 'package:blog_app/pages/profile_page.dart';
|
||||
import 'package:blog_app/pages/category_page.dart';
|
||||
import 'package:blog_app/pages/settings_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@@ -14,18 +15,6 @@ class _HomePageState extends State<HomePage> {
|
||||
int _currentPageIndex = 0;
|
||||
late PageController _pageController;
|
||||
|
||||
// 页面标题列表
|
||||
final List<String> _pageTitles = ['博客', '消息中心', '设置', '关于我们'];
|
||||
|
||||
// 页面图标列表
|
||||
final List<IconData> _pageIcons = [
|
||||
Icons.article,
|
||||
Icons.person,
|
||||
Icons.message,
|
||||
Icons.settings,
|
||||
Icons.info,
|
||||
];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -46,7 +35,7 @@ class _HomePageState extends State<HomePage> {
|
||||
_currentPageIndex = index;
|
||||
});
|
||||
},
|
||||
children: [BlogPage(), MessagePage(), SettingsPage(), AboutPage()],
|
||||
children: [BlogPage(), CategoryPage(), SettingsPage(), AboutPage()],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,7 +44,7 @@ class _HomePageState extends State<HomePage> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
_pageTitles[_currentPageIndex],
|
||||
pages[_currentPageIndex].title,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
@@ -79,6 +68,35 @@ class _HomePageState extends State<HomePage> {
|
||||
);
|
||||
}
|
||||
|
||||
void onTapDrawerItem(int index) {
|
||||
setState(() {
|
||||
_currentPageIndex = index;
|
||||
});
|
||||
_pageController.animateToPage(
|
||||
index,
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
Widget _buildDrawerBody() {
|
||||
return ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
...List.generate(
|
||||
pages.length,
|
||||
(index) => buildDrawerItem(
|
||||
context: context,
|
||||
page: pages[index],
|
||||
isSelected: index == _currentPageIndex,
|
||||
onTap: () => onTapDrawerItem(index),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDrawer() {
|
||||
return Drawer(
|
||||
child: Container(
|
||||
@@ -86,145 +104,12 @@ class _HomePageState extends State<HomePage> {
|
||||
child: Column(
|
||||
children: [
|
||||
// 抽屉头部
|
||||
_buildDrawerHeader(),
|
||||
|
||||
buildDrawerHeader(context),
|
||||
// 菜单项列表
|
||||
Expanded(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
...List.generate(
|
||||
_pageTitles.length,
|
||||
(index) => _buildDrawerItem(
|
||||
icon: _pageIcons[index],
|
||||
title: _pageTitles[index],
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(child: _buildDrawerBody()),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDrawerHeader() {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Colors.blue, Colors.lightBlue],
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 40,
|
||||
backgroundColor: Colors.white.withOpacity(0.3),
|
||||
child: Icon(Icons.person, size: 50, color: Colors.white),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
Text(
|
||||
'用户名',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Text(
|
||||
'user@example.com',
|
||||
style: TextStyle(color: Colors.white70, fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDrawerItem({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required int index,
|
||||
}) {
|
||||
final bool isSelected = index == _currentPageIndex;
|
||||
final bool isSpecialItem = index == -1; // 特殊菜单项标识
|
||||
|
||||
return Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected ? Colors.blue.withOpacity(0.1) : Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
icon,
|
||||
color:
|
||||
isSelected
|
||||
? Colors.blue
|
||||
: isSpecialItem
|
||||
? Colors.grey[600]
|
||||
: Colors.grey[700],
|
||||
size: 24,
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color:
|
||||
isSelected
|
||||
? Colors.blue
|
||||
: isSpecialItem
|
||||
? Colors.grey[600]
|
||||
: Colors.grey[800],
|
||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
trailing:
|
||||
isSelected
|
||||
? Icon(Icons.arrow_forward_ios, size: 16, color: Colors.blue)
|
||||
: null,
|
||||
onTap: () {
|
||||
if (!isSpecialItem) {
|
||||
// 正常页面切换
|
||||
setState(() {
|
||||
_currentPageIndex = index;
|
||||
});
|
||||
_pageController.animateToPage(
|
||||
index,
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
} else {
|
||||
// 特殊菜单项处理
|
||||
_handleSpecialItemTap(title);
|
||||
}
|
||||
Navigator.pop(context); // 关闭抽屉
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSpecialItemTap(String title) {
|
||||
// 处理特殊菜单项的点击事件
|
||||
switch (title) {
|
||||
case '帮助中心':
|
||||
print('打开帮助中心');
|
||||
break;
|
||||
case '意见反馈':
|
||||
print('打开意见反馈');
|
||||
break;
|
||||
case '退出登录':
|
||||
print('执行退出登录');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user