flutter实现web端实现效果
效果图



flutter 版本 sdk: '>=3.4.4 <4.0.0'
代码示例
新代码
dart
import 'package:flutter/material.dart';
void main() {
runApp(const NavigationRailApp());
}
class NavigationRailApp extends StatelessWidget {
const NavigationRailApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NavigationRail Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const MainNavigationScreen(),
);
}
}
class MainNavigationScreen extends StatefulWidget {
const MainNavigationScreen({super.key});
@override
State<MainNavigationScreen> createState() => _MainNavigationScreenState();
}
class _MainNavigationScreenState extends State<MainNavigationScreen> {
int _selectedMainIndex = 0;
int _selectedSubIndex = 0;
int _selectedDetailIndex = 0;
final List<NavigationCategory> _categories = [
NavigationCategory(
title: '产品管理',
icon: Icons.shopping_bag,
subCategories: [
SubCategory(
title: '手机数码',
items: [
DetailItem(
title: 'iPhone 15 Pro', description: '苹果最新旗舰手机', price: 7999),
DetailItem(
title: '三星 Galaxy S24', description: '三星旗舰智能手机', price: 5999),
DetailItem(title: '小米 14', description: '性价比旗舰手机', price: 3999),
],
),
SubCategory(
title: '家用电器',
items: [
DetailItem(title: '智能电视', description: '4K超高清智能电视', price: 2999),
DetailItem(title: '空调冰箱', description: '节能变频空调冰箱', price: 4599),
],
),
],
),
NavigationCategory(
title: '用户管理',
icon: Icons.people,
subCategories: [
SubCategory(
title: '会员用户',
items: [
DetailItem(title: 'VIP会员', description: '高级会员特权', price: 299),
DetailItem(title: '普通用户', description: '基础用户功能', price: 0),
],
),
SubCategory(
title: '权限管理',
items: [
DetailItem(title: '角色权限', description: '权限分配管理', price: 0),
DetailItem(title: '操作日志', description: '系统操作记录', price: 0),
],
),
],
),
NavigationCategory(
title: '订单管理',
icon: Icons.receipt,
subCategories: [
SubCategory(
title: '待处理订单',
items: [
DetailItem(title: '待付款', description: '等待用户付款的订单', price: 0),
DetailItem(title: '待发货', description: '等待商家发货的订单', price: 0),
],
),
SubCategory(
title: '已完成订单',
items: [
DetailItem(title: '已完成', description: '交易完成的订单', price: 0),
DetailItem(title: '已评价', description: '用户已评价的订单', price: 0),
],
),
],
),
];
final List<GlobalKey<NavigatorState>> _rightNavigatorKeys = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
// 固定左侧导航栏
FixedNavigationRail(
categories: _categories,
selectedMainIndex: _selectedMainIndex,
selectedSubIndex: _selectedSubIndex,
onMainIndexChanged: (index) {
setState(() {
_selectedMainIndex = index;
_selectedSubIndex = 0;
_selectedDetailIndex = 0;
});
},
onSubIndexChanged: (index) {
setState(() {
_selectedSubIndex = index;
_selectedDetailIndex = 0;
});
},
),
// 右侧内容区域
const VerticalDivider(thickness: 1, width: 1),
Expanded(
child: Navigator(
key: _rightNavigatorKeys[_selectedDetailIndex],
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: (BuildContext context) {
return _buildContentArea();
},
);
},
),
),
// 右侧内容区域
// Expanded(
// child: _buildContentArea(),
// ),
],
),
);
}
Widget _buildContentArea() {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.blue.shade50,
Colors.white,
],
),
),
child: _categories[_selectedMainIndex].buildContent(
selectedSubIndex: _selectedSubIndex,
selectedDetailIndex: _selectedDetailIndex,
onSubIndexChanged: (index) {
setState(() {
_selectedSubIndex = index;
_selectedDetailIndex = 0;
});
},
onDetailIndexChanged: (index) {
setState(() {
_selectedDetailIndex = index;
});
},
),
);
}
}
class NavigationCategory {
final String title;
final IconData icon;
final List<SubCategory> subCategories;
NavigationCategory({
required this.title,
required this.icon,
required this.subCategories,
});
Widget buildContent({
required int selectedSubIndex,
required int selectedDetailIndex,
required ValueChanged<int> onSubIndexChanged,
required ValueChanged<int> onDetailIndexChanged,
}) {
return CategoryContentPage(
category: this,
selectedSubIndex: selectedSubIndex,
selectedDetailIndex: selectedDetailIndex,
onSubIndexChanged: onSubIndexChanged,
onDetailIndexChanged: onDetailIndexChanged,
);
}
}
class SubCategory {
final String title;
final List<DetailItem> items;
SubCategory({
required this.title,
required this.items,
});
}
class DetailItem {
final String title;
final String description;
final double price;
DetailItem({
required this.title,
required this.description,
required this.price,
});
}
class FixedNavigationRail extends StatelessWidget {
final List<NavigationCategory> categories;
final int selectedMainIndex;
final int selectedSubIndex;
final ValueChanged<int> onMainIndexChanged;
final ValueChanged<int> onSubIndexChanged;
const FixedNavigationRail({
super.key,
required this.categories,
required this.selectedMainIndex,
required this.selectedSubIndex,
required this.onMainIndexChanged,
required this.onSubIndexChanged,
});
@override
Widget build(BuildContext context) {
return Container(
width: 280,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(2, 0),
),
],
border: Border(
right: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: Column(
children: [
_buildHeaderSection(),
_buildMainNavigationSection(),
],
),
);
}
Widget _buildHeaderSection() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: const Row(
children: [
Icon(Icons.dashboard, color: Colors.blue, size: 24),
SizedBox(width: 12),
Text(
'管理系统',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
),
);
}
Widget _buildMainNavigationSection() {
return Expanded(
child: ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
return _buildMainCategoryItem(categories[index], index);
},
),
);
}
Widget _buildMainCategoryItem(NavigationCategory category, int index) {
final isSelected = index == selectedMainIndex;
return Column(
children: [
ListTile(
leading: Icon(
category.icon,
color: isSelected ? Colors.blue : Colors.grey.shade600,
),
title: Text(
category.title,
style: TextStyle(
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
color: isSelected ? Colors.blue : Colors.grey.shade800,
),
),
tileColor: isSelected ? Colors.blue.shade50 : Colors.transparent,
selected: isSelected,
onTap: () => onMainIndexChanged(index),
),
if (isSelected) ..._buildSubCategoryItems(category),
],
);
}
List<Widget> _buildSubCategoryItems(NavigationCategory category) {
return category.subCategories.asMap().entries.map((entry) {
final subIndex = entry.key;
final subCategory = entry.value;
final isSubSelected = subIndex == selectedSubIndex;
return Padding(
padding: const EdgeInsets.only(left: 16),
child: ListTile(
leading: Icon(
Icons.folder,
color: isSubSelected ? Colors.blue : Colors.grey.shade600,
),
title: Text(
subCategory.title,
style: TextStyle(
fontSize: 14,
color: isSubSelected ? Colors.blue : Colors.grey.shade700,
),
),
tileColor: isSubSelected ? Colors.blue.shade50 : Colors.transparent,
selected: isSubSelected,
onTap: () => onSubIndexChanged(subIndex),
),
);
}).toList();
}
}
class CategoryContentPage extends StatelessWidget {
final NavigationCategory category;
final int selectedSubIndex;
final int selectedDetailIndex;
final ValueChanged<int> onSubIndexChanged;
final ValueChanged<int> onDetailIndexChanged;
const CategoryContentPage({
super.key,
required this.category,
required this.selectedSubIndex,
required this.selectedDetailIndex,
required this.onSubIndexChanged,
required this.onDetailIndexChanged,
});
@override
Widget build(BuildContext context) {
final subCategory = category.subCategories[selectedSubIndex];
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildPageHeader(),
const SizedBox(height: 20),
_buildSubCategorySelector(),
const SizedBox(height: 20),
Expanded(
child: _buildContentGrid(subCategory),
),
],
),
);
}
Widget _buildPageHeader() {
return Row(
children: [
Icon(category.icon, color: Colors.blue, size: 32),
const SizedBox(width: 12),
Text(
category.title,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
);
}
Widget _buildSubCategorySelector() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: category.subCategories.asMap().entries.map((entry) {
final index = entry.key;
final subCategory = entry.value;
final isSelected = index == selectedSubIndex;
return Padding(
padding: const EdgeInsets.only(right: 12),
child: ChoiceChip(
label: Text(subCategory.title),
selected: isSelected,
onSelected: (selected) {
if (selected) onSubIndexChanged(index);
},
),
);
}).toList(),
),
);
}
Widget _buildContentGrid(SubCategory subCategory) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 1.2,
),
itemCount: subCategory.items.length,
itemBuilder: (context, index) {
return _buildItemCard(context, subCategory.items[index], index);
},
);
}
Widget _buildItemCard(BuildContext context, DetailItem item, int index) {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
onDetailIndexChanged(index);
_navigateToDetailPage(context, item);
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.description, color: Colors.blue, size: 32),
const SizedBox(height: 8),
Text(
item.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Text(
item.description,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
const Spacer(),
if (item.price > 0)
Text(
'¥${item.price}',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
),
),
);
}
void _navigateToDetailPage(BuildContext context, DetailItem item) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ItemDetailPage(item: item),
),
);
}
}
class ItemDetailPage extends StatelessWidget {
final DetailItem item;
const ItemDetailPage({super.key, required this.item});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(item.title),
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
),
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDetailHeader(),
const SizedBox(height: 24),
_buildDetailContent(),
const SizedBox(height: 24),
_buildActionButtons(),
],
),
),
);
}
Widget _buildDetailHeader() {
return Row(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.description, color: Colors.blue, size: 32),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
item.description,
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade600,
),
),
],
),
),
],
);
}
Widget _buildDetailContent() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'详细信息',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
_buildInfoRow('产品名称', item.title),
_buildInfoRow('产品描述', item.description),
if (item.price > 0) _buildInfoRow('价格', '¥${item.price}'),
const SizedBox(height: 20),
const Text(
'操作说明',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
const SizedBox(height: 12),
Text(
'在这里可以执行相关的操作,如编辑、删除、查看历史记录等。',
style: TextStyle(color: Colors.grey.shade600),
),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
SizedBox(
width: 80,
child: Text(
'$label:',
style: TextStyle(
fontWeight: FontWeight.w500,
color: Colors.grey.shade700,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
value,
style: const TextStyle(fontSize: 14),
),
),
],
),
);
}
Widget _buildActionButtons() {
return Row(
children: [
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.edit),
label: const Text('编辑信息'),
onPressed: () {},
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
icon: const Icon(Icons.delete),
label: const Text('删除'),
onPressed: () {},
),
),
],
);
}
}
旧代码
dart
import 'package:flutter/material.dart';
void main() {
runApp(const NavigationRailApp());
}
class NavigationRailApp extends StatelessWidget {
const NavigationRailApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NavigationRail Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const MainNavigationScreen(),
);
}
}
class MainNavigationScreen extends StatefulWidget {
const MainNavigationScreen({super.key});
@override
State<MainNavigationScreen> createState() => _MainNavigationScreenState();
}
class _MainNavigationScreenState extends State<MainNavigationScreen> {
int _selectedMainIndex = 0;
int _selectedSubIndex = 0;
int _selectedDetailIndex = 0;
final List<NavigationCategory> _categories = [
NavigationCategory(
title: '产品管理',
icon: Icons.shopping_bag,
subCategories: [
SubCategory(
title: '手机数码',
items: [
DetailItem(
title: 'iPhone 15 Pro', description: '苹果最新旗舰手机', price: 7999),
DetailItem(
title: '三星 Galaxy S24', description: '三星旗舰智能手机', price: 5999),
DetailItem(title: '小米 14', description: '性价比旗舰手机', price: 3999),
],
),
SubCategory(
title: '家用电器',
items: [
DetailItem(title: '智能电视', description: '4K超高清智能电视', price: 2999),
DetailItem(title: '空调冰箱', description: '节能变频空调冰箱', price: 4599),
],
),
],
),
NavigationCategory(
title: '用户管理',
icon: Icons.people,
subCategories: [
SubCategory(
title: '会员用户',
items: [
DetailItem(title: 'VIP会员', description: '高级会员特权', price: 299),
DetailItem(title: '普通用户', description: '基础用户功能', price: 0),
],
),
SubCategory(
title: '权限管理',
items: [
DetailItem(title: '角色权限', description: '权限分配管理', price: 0),
DetailItem(title: '操作日志', description: '系统操作记录', price: 0),
],
),
],
),
NavigationCategory(
title: '订单管理',
icon: Icons.receipt,
subCategories: [
SubCategory(
title: '待处理订单',
items: [
DetailItem(title: '待付款', description: '等待用户付款的订单', price: 0),
DetailItem(title: '待发货', description: '等待商家发货的订单', price: 0),
],
),
SubCategory(
title: '已完成订单',
items: [
DetailItem(title: '已完成', description: '交易完成的订单', price: 0),
DetailItem(title: '已评价', description: '用户已评价的订单', price: 0),
],
),
],
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
// 固定左侧导航栏
FixedNavigationRail(
categories: _categories,
selectedMainIndex: _selectedMainIndex,
selectedSubIndex: _selectedSubIndex,
onMainIndexChanged: (index) {
setState(() {
_selectedMainIndex = index;
_selectedSubIndex = 0;
_selectedDetailIndex = 0;
});
},
onSubIndexChanged: (index) {
setState(() {
_selectedSubIndex = index;
_selectedDetailIndex = 0;
});
},
),
// 右侧内容区域
Expanded(
child: _buildContentArea(),
),
],
),
);
}
Widget _buildContentArea() {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.blue.shade50,
Colors.white,
],
),
),
child: _categories[_selectedMainIndex].buildContent(
selectedSubIndex: _selectedSubIndex,
selectedDetailIndex: _selectedDetailIndex,
onSubIndexChanged: (index) {
setState(() {
_selectedSubIndex = index;
_selectedDetailIndex = 0;
});
},
onDetailIndexChanged: (index) {
setState(() {
_selectedDetailIndex = index;
});
},
),
);
}
}
class NavigationCategory {
final String title;
final IconData icon;
final List<SubCategory> subCategories;
NavigationCategory({
required this.title,
required this.icon,
required this.subCategories,
});
Widget buildContent({
required int selectedSubIndex,
required int selectedDetailIndex,
required ValueChanged<int> onSubIndexChanged,
required ValueChanged<int> onDetailIndexChanged,
}) {
return CategoryContentPage(
category: this,
selectedSubIndex: selectedSubIndex,
selectedDetailIndex: selectedDetailIndex,
onSubIndexChanged: onSubIndexChanged,
onDetailIndexChanged: onDetailIndexChanged,
);
}
}
class SubCategory {
final String title;
final List<DetailItem> items;
SubCategory({
required this.title,
required this.items,
});
}
class DetailItem {
final String title;
final String description;
final double price;
DetailItem({
required this.title,
required this.description,
required this.price,
});
}
class FixedNavigationRail extends StatelessWidget {
final List<NavigationCategory> categories;
final int selectedMainIndex;
final int selectedSubIndex;
final ValueChanged<int> onMainIndexChanged;
final ValueChanged<int> onSubIndexChanged;
const FixedNavigationRail({
super.key,
required this.categories,
required this.selectedMainIndex,
required this.selectedSubIndex,
required this.onMainIndexChanged,
required this.onSubIndexChanged,
});
@override
Widget build(BuildContext context) {
return Container(
width: 280,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(2, 0),
),
],
border: Border(
right: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: Column(
children: [
_buildHeaderSection(),
_buildMainNavigationSection(),
],
),
);
}
Widget _buildHeaderSection() {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey.shade200,
width: 1,
),
),
),
child: const Row(
children: [
Icon(Icons.dashboard, color: Colors.blue, size: 24),
SizedBox(width: 12),
Text(
'管理系统',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
),
);
}
Widget _buildMainNavigationSection() {
return Expanded(
child: ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
return _buildMainCategoryItem(categories[index], index);
},
),
);
}
Widget _buildMainCategoryItem(NavigationCategory category, int index) {
final isSelected = index == selectedMainIndex;
return Column(
children: [
ListTile(
leading: Icon(
category.icon,
color: isSelected ? Colors.blue : Colors.grey.shade600,
),
title: Text(
category.title,
style: TextStyle(
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
color: isSelected ? Colors.blue : Colors.grey.shade800,
),
),
tileColor: isSelected ? Colors.blue.shade50 : Colors.transparent,
selected: isSelected,
onTap: () => onMainIndexChanged(index),
),
if (isSelected) ..._buildSubCategoryItems(category),
],
);
}
List<Widget> _buildSubCategoryItems(NavigationCategory category) {
return category.subCategories.asMap().entries.map((entry) {
final subIndex = entry.key;
final subCategory = entry.value;
final isSubSelected = subIndex == selectedSubIndex;
return Padding(
padding: const EdgeInsets.only(left: 16),
child: ListTile(
leading: Icon(
Icons.folder,
color: isSubSelected ? Colors.blue : Colors.grey.shade600,
),
title: Text(
subCategory.title,
style: TextStyle(
fontSize: 14,
color: isSubSelected ? Colors.blue : Colors.grey.shade700,
),
),
tileColor: isSubSelected ? Colors.blue.shade50 : Colors.transparent,
selected: isSubSelected,
onTap: () => onSubIndexChanged(subIndex),
),
);
}).toList();
}
}
class CategoryContentPage extends StatelessWidget {
final NavigationCategory category;
final int selectedSubIndex;
final int selectedDetailIndex;
final ValueChanged<int> onSubIndexChanged;
final ValueChanged<int> onDetailIndexChanged;
const CategoryContentPage({
super.key,
required this.category,
required this.selectedSubIndex,
required this.selectedDetailIndex,
required this.onSubIndexChanged,
required this.onDetailIndexChanged,
});
@override
Widget build(BuildContext context) {
final subCategory = category.subCategories[selectedSubIndex];
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildPageHeader(),
const SizedBox(height: 20),
_buildSubCategorySelector(),
const SizedBox(height: 20),
Expanded(
child: _buildContentGrid(subCategory),
),
],
),
);
}
Widget _buildPageHeader() {
return Row(
children: [
Icon(category.icon, color: Colors.blue, size: 32),
const SizedBox(width: 12),
Text(
category.title,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
);
}
Widget _buildSubCategorySelector() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: category.subCategories.asMap().entries.map((entry) {
final index = entry.key;
final subCategory = entry.value;
final isSelected = index == selectedSubIndex;
return Padding(
padding: const EdgeInsets.only(right: 12),
child: ChoiceChip(
label: Text(subCategory.title),
selected: isSelected,
onSelected: (selected) {
if (selected) onSubIndexChanged(index);
},
),
);
}).toList(),
),
);
}
Widget _buildContentGrid(SubCategory subCategory) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 1.2,
),
itemCount: subCategory.items.length,
itemBuilder: (context, index) {
return _buildItemCard(context, subCategory.items[index], index);
},
);
}
Widget _buildItemCard(BuildContext context, DetailItem item, int index) {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
onDetailIndexChanged(index);
_navigateToDetailPage(context, item);
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(Icons.description, color: Colors.blue, size: 32),
const SizedBox(height: 8),
Text(
item.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Text(
item.description,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
const Spacer(),
if (item.price > 0)
Text(
'¥${item.price}',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
],
),
),
),
);
}
void _navigateToDetailPage(BuildContext context, DetailItem item) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ItemDetailPage(item: item),
),
);
}
}
class ItemDetailPage extends StatelessWidget {
final DetailItem item;
const ItemDetailPage({super.key, required this.item});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(item.title),
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(context),
),
),
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDetailHeader(),
const SizedBox(height: 24),
_buildDetailContent(),
const SizedBox(height: 24),
_buildActionButtons(),
],
),
),
);
}
Widget _buildDetailHeader() {
return Row(
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.blue.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Icon(Icons.description, color: Colors.blue, size: 32),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item.title,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
item.description,
style: TextStyle(
fontSize: 16,
color: Colors.grey.shade600,
),
),
],
),
),
],
);
}
Widget _buildDetailContent() {
return Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'详细信息',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
_buildInfoRow('产品名称', item.title),
_buildInfoRow('产品描述', item.description),
if (item.price > 0) _buildInfoRow('价格', '¥${item.price}'),
const SizedBox(height: 20),
const Text(
'操作说明',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
const SizedBox(height: 12),
Text(
'在这里可以执行相关的操作,如编辑、删除、查看历史记录等。',
style: TextStyle(color: Colors.grey.shade600),
),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
SizedBox(
width: 80,
child: Text(
'$label:',
style: TextStyle(
fontWeight: FontWeight.w500,
color: Colors.grey.shade700,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
value,
style: const TextStyle(fontSize: 14),
),
),
],
),
);
}
Widget _buildActionButtons() {
return Row(
children: [
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.edit),
label: const Text('编辑信息'),
onPressed: () {},
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
icon: const Icon(Icons.delete),
label: const Text('删除'),
onPressed: () {},
),
),
],
);
}
}