Flutter 框架跨平台鸿蒙开发 - 非遗文化查询:传承中华文化瑰宝
非遗文化查询是一款专为非物质文化遗产保护和传播打造的Flutter应用,提供非遗项目查询、传承人信息展示和地域分布统计功能。通过智能搜索和分类筛选,让用户轻松了解和学习中华优秀传统文化。运行效果图模型字段说明:计算属性:非遗分类与颜色映射:保护等级:模型字段说明:计算属性:数据生成特点:筛选条件:筛选流程:搜索功能特点:筛选对话框设计:卡片布局结构:设计要点:卡片布局结构:设计要点:统计功能:页面
Flutter非遗文化查询:传承中华文化瑰宝
项目简介
非遗文化查询是一款专为非物质文化遗产保护和传播打造的Flutter应用,提供非遗项目查询、传承人信息展示和地域分布统计功能。通过智能搜索和分类筛选,让用户轻松了解和学习中华优秀传统文化。
运行效果图



核心功能
- 非遗项目查询:50个非遗项目,涵盖10大分类
- 传承人信息:30位传承人详细资料
- 智能搜索:支持项目名称、传承人、地区搜索
- 多维筛选:按分类、等级、省份筛选
- 详细信息:项目简介、历史渊源、特色展示
- 地域分布:可视化展示各省份非遗项目分布
- 等级标识:国家级、省级、市级、县级
- 传承状态:传承良好、濒危状态标识
- 收藏分享:收藏项目、分享功能
- 传承人档案:个人简介、成就、技艺、荣誉
技术特点
- Material Design 3设计风格
- NavigationBar底部导航
- 三页面架构(非遗项目、传承人、地域分布)
- 搜索和筛选功能
- 详情页展示
- 响应式卡片布局
- 数据可视化统计
- 无需额外依赖包
核心代码实现
1. 非遗项目数据模型
class HeritageProject {
final String id; // 项目ID
final String name; // 项目名称
final String category; // 分类
final String level; // 保护等级
final String province; // 省份
final String city; // 城市
final String description; // 项目简介
final String history; // 历史渊源
final String features; // 项目特色
final String status; // 传承状态
final List<String> tags; // 标签
final DateTime approvalDate; // 批准时间
final int batchNumber; // 批次
HeritageProject({
required this.id,
required this.name,
required this.category,
required this.level,
required this.province,
required this.city,
required this.description,
required this.history,
required this.features,
required this.status,
required this.tags,
required this.approvalDate,
required this.batchNumber,
});
// 分类颜色
Color get categoryColor {
switch (category) {
case '民间文学': return Colors.purple;
case '传统音乐': return Colors.blue;
case '传统舞蹈': return Colors.pink;
case '传统戏剧': return Colors.red;
case '曲艺': return Colors.orange;
case '传统体育': return Colors.green;
case '传统美术': return Colors.indigo;
case '传统技艺': return Colors.teal;
case '传统医药': return Colors.cyan;
case '民俗': return Colors.amber;
default: return Colors.grey;
}
}
// 分类图标
IconData get categoryIcon {
switch (category) {
case '民间文学': return Icons.menu_book;
case '传统音乐': return Icons.music_note;
case '传统舞蹈': return Icons.theater_comedy;
case '传统戏剧': return Icons.masks;
case '曲艺': return Icons.mic;
case '传统体育': return Icons.sports_martial_arts;
case '传统美术': return Icons.palette;
case '传统技艺': return Icons.handyman;
case '传统医药': return Icons.medical_services;
case '民俗': return Icons.festival;
default: return Icons.category;
}
}
// 等级颜色
Color get levelColor {
switch (level) {
case '国家级': return Colors.red;
case '省级': return Colors.orange;
case '市级': return Colors.blue;
case '县级': return Colors.green;
default: return Colors.grey;
}
}
}
模型字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 唯一标识符 |
| name | String | 项目名称 |
| category | String | 分类(10大类) |
| level | String | 保护等级 |
| province | String | 所属省份 |
| city | String | 所属城市 |
| description | String | 项目简介 |
| history | String | 历史渊源 |
| features | String | 项目特色 |
| status | String | 传承状态 |
| tags | List | 标签列表 |
| approvalDate | DateTime | 批准时间 |
| batchNumber | int | 批次编号 |
计算属性:
categoryColor:根据分类返回对应颜色categoryIcon:根据分类返回对应图标levelColor:根据等级返回对应颜色
非遗分类与颜色映射:
| 分类 | 颜色 | 图标 | 说明 |
|---|---|---|---|
| 民间文学 | 紫色 | menu_book | 神话、传说、故事等 |
| 传统音乐 | 蓝色 | music_note | 民歌、器乐等 |
| 传统舞蹈 | 粉色 | theater_comedy | 民间舞蹈 |
| 传统戏剧 | 红色 | masks | 戏曲、曲艺等 |
| 曲艺 | 橙色 | mic | 说唱艺术 |
| 传统体育 | 绿色 | sports_martial_arts | 武术、竞技等 |
| 传统美术 | 靛蓝 | palette | 绘画、雕刻等 |
| 传统技艺 | 青色 | handyman | 手工技艺 |
| 传统医药 | 青色 | medical_services | 中医药等 |
| 民俗 | 琥珀色 | festival | 节日、礼仪等 |
保护等级:
| 等级 | 颜色 | 说明 |
|---|---|---|
| 国家级 | 红色 | 国家级非遗项目 |
| 省级 | 橙色 | 省级非遗项目 |
| 市级 | 蓝色 | 市级非遗项目 |
| 县级 | 绿色 | 县级非遗项目 |
2. 传承人数据模型
class Inheritor {
final String id; // 传承人ID
final String name; // 姓名
final String gender; // 性别
final int age; // 年龄
final String projectName; // 传承项目
final String level; // 传承等级
final String province; // 省份
final String city; // 城市
final String introduction; // 个人简介
final String achievements; // 主要成就
final String skills; // 技艺特长
final List<String> awards; // 获得荣誉
final DateTime recognitionDate; // 认定时间
Inheritor({
required this.id,
required this.name,
required this.gender,
required this.age,
required this.projectName,
required this.level,
required this.province,
required this.city,
required this.introduction,
required this.achievements,
required this.skills,
required this.awards,
required this.recognitionDate,
});
// 等级颜色
Color get levelColor {
switch (level) {
case '国家级': return Colors.red;
case '省级': return Colors.orange;
case '市级': return Colors.blue;
case '县级': return Colors.green;
default: return Colors.grey;
}
}
}
模型字段说明:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | 唯一标识符 |
| name | String | 传承人姓名 |
| gender | String | 性别 |
| age | int | 年龄 |
| projectName | String | 传承项目名称 |
| level | String | 传承等级 |
| province | String | 所在省份 |
| city | String | 所在城市 |
| introduction | String | 个人简介 |
| achievements | String | 主要成就 |
| skills | String | 技艺特长 |
| awards | List | 荣誉列表 |
| recognitionDate | DateTime | 认定时间 |
计算属性:
levelColor:根据传承等级返回对应颜色
3. 数据生成逻辑
void _generateData() {
final random = Random();
// 非遗项目名称库
final projectNames = [
'昆曲', '古琴艺术', '木版水印', '景泰蓝制作技艺', '京剧',
'越剧', '黄梅戏', '评剧', '豫剧', '川剧', '秦腔', '粤剧',
'湘绣', '苏绣', '蜀绣', '剪纸', '皮影戏', '木偶戏',
'龙舟竞渡', '太极拳', '少林功夫', '武当武术', '中医针灸',
'藏医药', '蒙医药', '景德镇瓷器', '宜兴紫砂', '龙泉青瓷',
'德化白瓷', '钧瓷', '汝瓷', '定瓷', '哥窑', '官窑', '建盏',
'漆器髹饰', '金银细工', '玉雕', '木雕', '石雕', '竹编',
'藤编', '草编', '柳编', '棕编', '扎染', '蜡染', '蓝印花布',
];
// 生成50个非遗项目
for (int i = 0; i < 50; i++) {
final category = _categories[random.nextInt(_categories.length - 1) + 1];
final level = _levels[random.nextInt(_levels.length - 1) + 1];
final province = _provinces[random.nextInt(_provinces.length - 1) + 1];
_allProjects.add(HeritageProject(
id: 'project_$i',
name: projectNames[i % projectNames.length],
category: category,
level: level,
province: province,
city: '${province.replaceAll('省', '').replaceAll('市', '').replaceAll('壮族自治区', '')}市',
description: '这是一项具有深厚历史底蕴和独特艺术价值的非物质文化遗产项目,代表了中华民族优秀传统文化的精髓。',
history: '该项目起源于${1000 + random.nextInt(1000)}年前,历经数代传承,形成了独特的艺术风格和技艺体系。',
features: '具有鲜明的地域特色、精湛的技艺水平、深厚的文化内涵和广泛的群众基础。',
status: random.nextDouble() > 0.3 ? '传承良好' : '濒危',
tags: ['传统文化', '非遗保护', '文化传承'],
approvalDate: DateTime.now().subtract(Duration(days: random.nextInt(3650))),
batchNumber: random.nextInt(5) + 1,
));
}
// 传承人名称库
final inheritorNames = [
'张大师', '李传人', '王艺人', '赵师傅', '刘老师', '陈大师',
'杨传人', '周艺人', '吴师傅', '郑老师', '孙大师', '朱传人',
'胡艺人', '林师傅', '何老师', '高大师', '梁传人', '郭艺人',
'马师傅', '罗老师', '宋大师', '唐传人', '韩艺人', '冯师傅',
'于老师', '董大师', '萧传人', '程艺人', '曹师傅', '袁老师',
];
// 生成30位传承人
for (int i = 0; i < 30; i++) {
final project = _allProjects[random.nextInt(_allProjects.length)];
final level = _levels[random.nextInt(_levels.length - 1) + 1];
_allInheritors.add(Inheritor(
id: 'inheritor_$i',
name: inheritorNames[i % inheritorNames.length],
gender: random.nextDouble() > 0.3 ? '男' : '女',
age: 40 + random.nextInt(40),
projectName: project.name,
level: level,
province: project.province,
city: project.city,
introduction: '从事${project.name}技艺传承${20 + random.nextInt(30)}年,是该项目的代表性传承人。',
achievements: '多次参加国内外文化交流活动,作品获得多项荣誉,培养学徒${10 + random.nextInt(50)}余人。',
skills: '精通${project.name}的各项技艺,在传统技法基础上有所创新和发展。',
awards: ['非遗传承人', '工艺美术大师', '文化传承贡献奖'],
recognitionDate: DateTime.now().subtract(Duration(days: random.nextInt(1825))),
));
}
_applyFilters();
}
数据生成特点:
- 生成50个非遗项目
- 生成30位传承人
- 随机分配分类、等级、省份
- 传承人与项目关联
- 年龄范围:40-80岁
- 传承年限:20-50年
- 培养学徒:10-60人
- 70%传承良好,30%濒危
4. 搜索和筛选功能
void _applyFilters() {
setState(() {
// 筛选非遗项目
_filteredProjects = _allProjects.where((project) {
// 搜索关键词筛选
if (_searchQuery.isNotEmpty) {
final query = _searchQuery.toLowerCase();
if (!project.name.toLowerCase().contains(query) &&
!project.province.toLowerCase().contains(query) &&
!project.city.toLowerCase().contains(query)) {
return false;
}
}
// 分类筛选
if (_selectedCategory != '全部' && project.category != _selectedCategory) {
return false;
}
// 等级筛选
if (_selectedLevel != '全部' && project.level != _selectedLevel) {
return false;
}
// 省份筛选
if (_selectedProvince != '全部' && project.province != _selectedProvince) {
return false;
}
return true;
}).toList();
// 筛选传承人
_filteredInheritors = _allInheritors.where((inheritor) {
// 搜索关键词筛选
if (_searchQuery.isNotEmpty) {
final query = _searchQuery.toLowerCase();
if (!inheritor.name.toLowerCase().contains(query) &&
!inheritor.projectName.toLowerCase().contains(query) &&
!inheritor.province.toLowerCase().contains(query)) {
return false;
}
}
// 等级筛选
if (_selectedLevel != '全部' && inheritor.level != _selectedLevel) {
return false;
}
// 省份筛选
if (_selectedProvince != '全部' && inheritor.province != _selectedProvince) {
return false;
}
return true;
}).toList();
});
}
筛选条件:
| 筛选项 | 适用对象 | 说明 |
|---|---|---|
| 搜索关键词 | 项目、传承人 | 匹配名称、地区 |
| 分类 | 项目 | 10大分类筛选 |
| 等级 | 项目、传承人 | 4个等级筛选 |
| 省份 | 项目、传承人 | 20个省份筛选 |
筛选流程:
- 检查搜索关键词匹配
- 检查分类匹配(仅项目)
- 检查等级匹配
- 检查省份匹配
- 更新筛选结果列表
5. 搜索栏组件
Widget _buildSearchBar() {
return Container(
padding: const EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
hintText: '搜索非遗项目、传承人或地区',
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
),
onChanged: (value) {
setState(() {
_searchQuery = value;
_applyFilters();
});
},
),
);
}
搜索功能特点:
- 实时搜索
- 支持项目名称搜索
- 支持传承人姓名搜索
- 支持地区搜索
- 不区分大小写
- 自动触发筛选
6. 筛选对话框
Widget _buildFilterSheet() {
return Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'筛选条件',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
// 分类筛选
DropdownButtonFormField<String>(
value: _selectedCategory,
decoration: const InputDecoration(
labelText: '分类',
border: OutlineInputBorder(),
),
items: _categories.map((category) {
return DropdownMenuItem(
value: category,
child: Text(category),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCategory = value!;
_applyFilters();
});
Navigator.pop(context);
},
),
const SizedBox(height: 16),
// 等级筛选
DropdownButtonFormField<String>(
value: _selectedLevel,
decoration: const InputDecoration(
labelText: '等级',
border: OutlineInputBorder(),
),
items: _levels.map((level) {
return DropdownMenuItem(
value: level,
child: Text(level),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedLevel = value!;
_applyFilters();
});
Navigator.pop(context);
},
),
const SizedBox(height: 16),
// 省份筛选
DropdownButtonFormField<String>(
value: _selectedProvince,
decoration: const InputDecoration(
labelText: '省份',
border: OutlineInputBorder(),
),
items: _provinces.map((province) {
return DropdownMenuItem(
value: province,
child: Text(province),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedProvince = value!;
_applyFilters();
});
Navigator.pop(context);
},
),
],
),
);
}
筛选对话框设计:
- 使用ModalBottomSheet展示
- 三个下拉选择框
- 选择后自动应用筛选
- 自动关闭对话框
7. 非遗项目卡片
Widget _buildProjectCard(HeritageProject project) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ProjectDetailPage(project: project),
),
);
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 顶部:图标、名称、等级、分类
Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: project.categoryColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Icon(
project.categoryIcon,
color: project.categoryColor,
size: 32,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
project.name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Row(
children: [
// 等级标签
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: project.levelColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
project.level,
style: const TextStyle(
fontSize: 12,
color: Colors.white,
),
),
),
const SizedBox(width: 8),
// 分类标签
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: project.categoryColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
project.category,
style: TextStyle(
fontSize: 12,
color: project.categoryColor,
),
),
),
],
),
],
),
),
],
),
const SizedBox(height: 12),
// 项目简介
Text(
project.description,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
height: 1.5,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 12),
// 底部:地区、传承状态
Row(
children: [
const Icon(Icons.location_on, size: 16, color: Colors.grey),
const SizedBox(width: 4),
Text(
'${project.province} ${project.city}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
const Spacer(),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: project.status == '传承良好'
? Colors.green.withValues(alpha: 0.1)
: Colors.red.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
),
child: Text(
project.status,
style: TextStyle(
fontSize: 12,
color: project.status == '传承良好'
? Colors.green
: Colors.red,
),
),
),
],
),
],
),
),
),
);
}
卡片布局结构:
- 顶部:分类图标、项目名称、等级标签、分类标签
- 中部:项目简介(最多2行)
- 底部:地区信息、传承状态标签
设计要点:
- 使用Card提供阴影效果
- InkWell提供点击反馈
- 图标使用分类颜色背景
- 标签使用圆角设计
- 传承状态用颜色区分
8. 传承人卡片
Widget _buildInheritorCard(Inheritor inheritor) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => InheritorDetailPage(inheritor: inheritor),
),
);
},
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
// 头像
CircleAvatar(
radius: 32,
backgroundColor: Colors.deepOrange.withValues(alpha: 0.1),
child: Text(
inheritor.name.substring(0, 1),
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
),
const SizedBox(width: 16),
// 信息
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
inheritor.name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
Text(
'${inheritor.gender} · ${inheritor.age}岁',
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
decoration: BoxDecoration(
color: inheritor.levelColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
'${inheritor.level}传承人',
style: const TextStyle(
fontSize: 12,
color: Colors.white,
),
),
),
const SizedBox(height: 8),
Text(
inheritor.projectName,
style: const TextStyle(
fontSize: 14,
color: Colors.deepOrange,
),
),
const SizedBox(height: 4),
Row(
children: [
const Icon(Icons.location_on, size: 14, color: Colors.grey),
const SizedBox(width: 4),
Text(
'${inheritor.province} ${inheritor.city}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
],
),
),
const Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey),
],
),
),
),
);
}
卡片布局结构:
- 左侧:圆形头像(显示姓氏首字)
- 中间:姓名、性别年龄、等级标签、传承项目、地区
- 右侧:箭头图标
设计要点:
- CircleAvatar显示头像
- 等级标签使用对应颜色
- 传承项目使用主题色
- 地区信息带图标
9. 地域分布统计页
Widget _buildMapPage() {
// 统计各省份的非遗项目数量
final provinceCount = <String, int>{};
for (var project in _allProjects) {
provinceCount[project.province] = (provinceCount[project.province] ?? 0) + 1;
}
// 按数量降序排序
final sortedProvinces = provinceCount.entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
return ListView(
padding: const EdgeInsets.all(16),
children: [
// 统计概览卡片
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.bar_chart, color: Colors.deepOrange),
SizedBox(width: 8),
Text(
'地域分布统计',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
Text(
'共收录 ${_allProjects.length} 个非遗项目',
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
Text(
'涉及 ${provinceCount.length} 个省份',
style: const TextStyle(fontSize: 14, color: Colors.grey),
),
],
),
),
),
const SizedBox(height: 16),
// 各省份统计卡片
...sortedProvinces.map((entry) {
final percentage = (entry.value / _allProjects.length * 100);
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
entry.key,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
'${entry.value} 项',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
],
),
const SizedBox(height: 8),
LinearProgressIndicator(
value: percentage / 100,
backgroundColor: Colors.grey[200],
color: Colors.deepOrange,
),
const SizedBox(height: 4),
Text(
'占比 ${percentage.toStringAsFixed(1)}%',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
),
);
}),
],
);
}
统计功能:
- 统计各省份非遗项目数量
- 按数量降序排序
- 计算占比百分比
- 使用进度条可视化展示
页面结构:
- 顶部:统计概览卡片
- 列表:各省份统计卡片
可视化设计:
- LinearProgressIndicator显示占比
- 进度条颜色使用主题色
- 显示具体数量和百分比
10. 非遗项目详情页
class ProjectDetailPage extends StatelessWidget {
final HeritageProject project;
const ProjectDetailPage({super.key, required this.project});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(project.name),
actions: [
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已添加到收藏')),
);
},
icon: const Icon(Icons.favorite_border),
tooltip: '收藏',
),
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('分享功能')),
);
},
icon: const Icon(Icons.share),
tooltip: '分享',
),
],
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
_buildBasicInfo(),
_buildDescription(),
_buildHistory(),
_buildFeatures(),
_buildTags(),
],
),
),
);
}
// 头部展示
Widget _buildHeader() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
project.categoryColor.withValues(alpha: 0.3),
project.categoryColor.withValues(alpha: 0.1),
],
),
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
child: Icon(
project.categoryIcon,
size: 64,
color: project.categoryColor,
),
),
const SizedBox(height: 16),
Text(
project.name,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
decoration: BoxDecoration(
color: project.levelColor,
borderRadius: BorderRadius.circular(12),
),
child: Text(
project.level,
style: const TextStyle(color: Colors.white),
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
decoration: BoxDecoration(
color: project.categoryColor.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(12),
),
child: Text(
project.category,
style: TextStyle(color: project.categoryColor),
),
),
],
),
],
),
);
}
// 基本信息
Widget _buildBasicInfo() {
return Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.info_outline, color: Colors.deepOrange),
SizedBox(width: 8),
Text(
'基本信息',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
_buildInfoRow('所属地区', '${project.province} ${project.city}'),
_buildInfoRow('保护等级', project.level),
_buildInfoRow('项目类别', project.category),
_buildInfoRow(
'批准时间',
'${project.approvalDate.year}年${project.approvalDate.month}月',
),
_buildInfoRow('批次', '第${project.batchNumber}批'),
_buildInfoRow('传承状态', project.status),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 80,
child: Text(
label,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
),
Expanded(
child: Text(
value,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
),
],
),
);
}
}
详情页结构:
- 头部:渐变背景、大图标、项目名称、等级分类标签
- 基本信息卡片:地区、等级、类别、批准时间、批次、传承状态
- 项目简介卡片:详细描述
- 历史渊源卡片:历史背景
- 项目特色卡片:特色介绍
- 相关标签卡片:标签展示
设计要点:
- 使用渐变背景突出头部
- 卡片式布局清晰分区
- 图标配合文字说明
- 信息行左右对齐
11. 传承人详情页
class InheritorDetailPage extends StatelessWidget {
final Inheritor inheritor;
const InheritorDetailPage({super.key, required this.inheritor});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(inheritor.name),
actions: [
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已添加到关注')),
);
},
icon: const Icon(Icons.person_add),
tooltip: '关注',
),
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('分享功能')),
);
},
icon: const Icon(Icons.share),
tooltip: '分享',
),
],
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
_buildBasicInfo(),
_buildIntroduction(),
_buildAchievements(),
_buildSkills(),
_buildAwards(),
],
),
),
);
}
// 头部展示
Widget _buildHeader() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.deepOrange.withValues(alpha: 0.3),
Colors.deepOrange.withValues(alpha: 0.1),
],
),
),
child: Column(
children: [
CircleAvatar(
radius: 48,
backgroundColor: Colors.white,
child: Text(
inheritor.name.substring(0, 1),
style: const TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
),
),
),
const SizedBox(height: 16),
Text(
inheritor.name,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 6,
),
decoration: BoxDecoration(
color: inheritor.levelColor,
borderRadius: BorderRadius.circular(16),
),
child: Text(
'${inheritor.level}传承人',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 8),
Text(
'${inheritor.gender} · ${inheritor.age}岁',
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
],
),
);
}
// 获得荣誉
Widget _buildAwards() {
return Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.military_tech, color: Colors.deepOrange),
SizedBox(width: 8),
Text(
'获得荣誉',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12),
...inheritor.awards.map((award) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.deepOrange.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Colors.deepOrange.withValues(alpha: 0.2),
),
),
child: Row(
children: [
const Icon(
Icons.star,
color: Colors.deepOrange,
size: 20,
),
const SizedBox(width: 8),
Text(
award,
style: const TextStyle(fontSize: 14),
),
],
),
);
}),
],
),
),
);
}
}
详情页结构:
- 头部:渐变背景、大头像、姓名、等级标签、性别年龄
- 基本信息卡片:传承项目、地区、等级、认定时间
- 个人简介卡片:传承经历
- 主要成就卡片:成就介绍
- 技艺特长卡片:技艺描述
- 获得荣誉卡片:荣誉列表
设计要点:
- 大头像突出人物
- 荣誉列表使用边框卡片
- 星标图标装饰荣誉项
- 渐变背景营造氛围
技术要点详解
1. NavigationBar底部导航
NavigationBar是Material Design 3中的底部导航组件,提供现代化的导航体验。
基本用法:
NavigationBar(
selectedIndex: _selectedIndex,
onDestinationSelected: (index) {
setState(() => _selectedIndex = index);
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.category),
label: '非遗项目',
),
NavigationDestination(
icon: Icon(Icons.people),
label: '传承人',
),
NavigationDestination(
icon: Icon(Icons.map),
label: '地域分布',
),
],
)
关键属性:
selectedIndex:当前选中的索引onDestinationSelected:选择回调函数destinations:导航项列表
配合IndexedStack使用:
IndexedStack(
index: _selectedIndex,
children: [
_buildProjectsPage(),
_buildInheritorsPage(),
_buildMapPage(),
],
)
优势:
- 保持页面状态
- 切换流畅无闪烁
- 符合Material Design 3规范
- 自动处理选中状态
2. 计算属性的高级应用
计算属性可以根据对象状态动态返回值,减少数据冗余。
示例:
class HeritageProject {
String category;
// 根据分类返回颜色
Color get categoryColor {
switch (category) {
case '民间文学': return Colors.purple;
case '传统音乐': return Colors.blue;
case '传统舞蹈': return Colors.pink;
// ... 更多分类
default: return Colors.grey;
}
}
// 根据分类返回图标
IconData get categoryIcon {
switch (category) {
case '民间文学': return Icons.menu_book;
case '传统音乐': return Icons.music_note;
case '传统舞蹈': return Icons.theater_comedy;
// ... 更多分类
default: return Icons.category;
}
}
String level;
// 根据等级返回颜色
Color get levelColor {
switch (level) {
case '国家级': return Colors.red;
case '省级': return Colors.orange;
case '市级': return Colors.blue;
case '县级': return Colors.green;
default: return Colors.grey;
}
}
}
优势:
- 减少存储空间
- 保持数据一致性
- 简化代码逻辑
- 便于维护和扩展
- 避免重复计算
使用场景:
- UI颜色映射
- 图标映射
- 状态文本转换
- 格式化显示
3. List集合操作
Dart的List提供了丰富的集合操作方法,用于数据筛选和处理。
筛选操作:
// 使用where筛选
final filteredProjects = _allProjects.where((project) {
if (_searchQuery.isNotEmpty) {
final query = _searchQuery.toLowerCase();
if (!project.name.toLowerCase().contains(query)) {
return false;
}
}
if (_selectedCategory != '全部' && project.category != _selectedCategory) {
return false;
}
return true;
}).toList();
排序操作:
// 按数量降序排序
final sortedProvinces = provinceCount.entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
统计操作:
// 统计各省份数量
final provinceCount = <String, int>{};
for (var project in _allProjects) {
provinceCount[project.province] = (provinceCount[project.province] ?? 0) + 1;
}
映射操作:
// 提取特定字段
final projectNames = _allProjects.map((p) => p.name).toList();
常用方法:
where:筛选元素map:转换元素sort:排序reduce:聚合fold:累积any:是否存在every:是否全部满足
4. ModalBottomSheet对话框
ModalBottomSheet用于从底部弹出的对话框,适合展示选项和筛选条件。
基本用法:
showModalBottomSheet(
context: context,
builder: (context) => Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 对话框内容
],
),
),
);
关键属性:
context:上下文builder:构建器函数isScrollControlled:是否可滚动shape:形状backgroundColor:背景颜色
使用场景:
- 筛选条件选择
- 选项列表
- 操作菜单
- 表单输入
设计要点:
- 使用
mainAxisSize: MainAxisSize.min自适应高度 - 添加圆角提升美观度
- 选择后自动关闭对话框
- 提供清晰的标题说明
5. DropdownButtonFormField下拉选择
DropdownButtonFormField是带表单样式的下拉选择组件。
基本用法:
DropdownButtonFormField<String>(
value: _selectedCategory,
decoration: const InputDecoration(
labelText: '分类',
border: OutlineInputBorder(),
),
items: _categories.map((category) {
return DropdownMenuItem(
value: category,
child: Text(category),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCategory = value!;
_applyFilters();
});
},
)
关键属性:
value:当前选中值decoration:装饰配置items:选项列表onChanged:选择回调
使用技巧:
- 使用泛型指定值类型
- 提供清晰的标签
- 选择后立即应用
- 配合InputDecoration美化
6. LinearProgressIndicator进度条
LinearProgressIndicator用于显示线性进度,适合可视化数据占比。
基本用法:
LinearProgressIndicator(
value: percentage / 100,
backgroundColor: Colors.grey[200],
color: Colors.deepOrange,
)
关键属性:
value:进度值(0-1)backgroundColor:背景颜色color:进度颜色minHeight:最小高度
使用场景:
- 数据占比展示
- 加载进度
- 统计可视化
- 完成度显示
设计要点:
- 配合百分比文字说明
- 使用主题色保持一致性
- 设置合适的高度
- 添加背景色对比
7. 渐变背景设计
使用LinearGradient创建渐变背景,提升视觉效果。
基本用法:
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
project.categoryColor.withValues(alpha: 0.3),
project.categoryColor.withValues(alpha: 0.1),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: // 内容
)
关键属性:
colors:颜色列表begin:起始位置end:结束位置stops:颜色停止点
使用场景:
- 页面头部背景
- 卡片背景
- 按钮背景
- 装饰元素
设计技巧:
- 使用透明度创建柔和效果
- 颜色过渡自然
- 配合内容颜色
- 避免过于鲜艳
8. 状态管理最佳实践
在非遗文化查询应用中的状态管理。
状态变量:
int _selectedIndex = 0; // 选中页面索引
List<HeritageProject> _allProjects = []; // 所有项目
List<HeritageProject> _filteredProjects = []; // 筛选后项目
List<Inheritor> _allInheritors = []; // 所有传承人
List<Inheritor> _filteredInheritors = []; // 筛选后传承人
String _searchQuery = ''; // 搜索关键词
String _selectedCategory = '全部'; // 选中分类
String _selectedLevel = '全部'; // 选中等级
String _selectedProvince = '全部'; // 选中省份
状态更新:
void _applyFilters() {
setState(() {
// 更新筛选结果
_filteredProjects = _allProjects.where((project) {
// 筛选逻辑
return true;
}).toList();
_filteredInheritors = _allInheritors.where((inheritor) {
// 筛选逻辑
return true;
}).toList();
});
}
最佳实践:
- 只在setState中修改状态
- 避免在build方法中修改状态
- 合理拆分Widget减少重建范围
- 使用const构造函数优化性能
- 及时清理不用的监听器
9. 数据模型设计
良好的数据模型设计是应用的基础。
模型层次:
HeritageProject (非遗项目)
├── 基本信息(名称、分类、等级)
├── 地理信息(省份、城市)
├── 详细信息(简介、历史、特色)
└── 元数据(批准时间、批次、状态)
Inheritor (传承人)
├── 个人信息(姓名、性别、年龄)
├── 传承信息(项目、等级)
├── 地理信息(省份、城市)
└── 详细信息(简介、成就、技艺、荣誉)
设计原则:
- 字段命名清晰
- 类型选择合理
- 提供计算属性
- 避免数据冗余
- 便于扩展
10. 性能优化技巧
提升应用性能的实用技巧。
ListView优化:
// 使用ListView.builder实现懒加载
ListView.builder(
itemCount: _filteredProjects.length,
itemBuilder: (context, index) {
return _buildProjectCard(_filteredProjects[index]);
},
)
const构造函数:
// 使用const减少重建
const Text('非遗文化查询')
const Icon(Icons.category)
const SizedBox(height: 16)
避免不必要的重建:
// 将不变的Widget提取为独立组件
class StaticHeader extends StatelessWidget {
const StaticHeader({super.key});
Widget build(BuildContext context) {
return const Text('标题');
}
}
优化筛选逻辑:
// 提前返回,减少不必要的判断
if (_searchQuery.isNotEmpty) {
final query = _searchQuery.toLowerCase();
if (!project.name.toLowerCase().contains(query)) {
return false; // 提前返回
}
}
性能优化建议:
- 使用ListView.builder懒加载
- 合理使用const
- 避免在build中创建对象
- 减少Widget嵌套层级
- 使用Key优化列表性能
功能扩展方向
1. 真实数据接入
接入真实的非遗数据API,提供准确的项目和传承人信息。
实现思路:
- 接入文化和旅游部非遗数据库API
- 使用地方非遗保护中心数据
- 定期更新数据
- 缓存数据到本地
- 离线模式支持
数据来源:
- 国家级非遗名录
- 省级非遗名录
- 市县级非遗名录
- 传承人数据库
- 非遗保护单位信息
2. 地图可视化
在地图上标注非遗项目和传承人位置,提供地理可视化。
实现思路:
- 集成地图SDK
- 标注项目位置
- 显示传承人分布
- 支持地图缩放
- 点击标注查看详情
功能设计:
- 热力图展示密度
- 聚合标注
- 路线规划
- 周边查询
- 地图筛选
3. 视频和图片展示
添加多媒体内容,更直观展示非遗项目。
实现思路:
- 项目展示视频
- 技艺演示视频
- 作品图片展示
- 传承人照片
- 活动现场图片
功能设计:
- 视频播放器
- 图片画廊
- 全屏查看
- 下载保存
- 分享功能
4. 学习和体验
提供非遗学习和体验功能。
实现思路:
- 在线课程
- 视频教程
- 技艺讲解
- 互动问答
- 学习打卡
功能设计:
- 课程列表
- 学习进度
- 证书获取
- 社区交流
- 作品展示
5. 活动和展览
展示非遗相关活动和展览信息。
实现思路:
- 活动日历
- 展览信息
- 在线报名
- 活动提醒
- 签到打卡
功能设计:
- 活动列表
- 详情页面
- 地图导航
- 评价反馈
- 照片分享
6. 收藏和关注
支持收藏项目和关注传承人。
实现思路:
- 收藏项目列表
- 关注传承人列表
- 同步到云端
- 推送更新通知
- 分享收藏
功能设计:
- 收藏夹管理
- 分类整理
- 导出功能
- 批量操作
- 推荐相似
7. 社交互动
添加社交功能,促进文化交流。
实现思路:
- 评论功能
- 点赞功能
- 分享功能
- 话题讨论
- 用户互动
功能设计:
- 评论区
- 点赞统计
- 分享到社交平台
- 话题标签
- 用户主页
8. 数据统计分析
提供更详细的数据统计和分析。
实现思路:
- 项目数量趋势
- 地域分布分析
- 传承人年龄分析
- 濒危项目统计
- 保护成效评估
功能设计:
- 图表展示
- 数据导出
- 报告生成
- 对比分析
- 预测趋势
常见问题解答
1. 如何获取真实的非遗数据?
问题:模拟数据不够真实,如何获取真实的非遗数据?
解答:
可以通过以下途径获取真实数据:
-
官方数据源:
- 文化和旅游部官网
- 中国非物质文化遗产网
- 各省文化厅官网
- 地方非遗保护中心
-
开放数据平台:
- 政府开放数据平台
- 文化数据开放平台
- 学术数据库
-
数据采集:
- 网络爬虫采集
- 人工整理
- 合作获取
注意事项:
- 遵守数据使用规范
- 注明数据来源
- 定期更新数据
- 保护隐私信息
2. 如何实现地图标注功能?
问题:如何在地图上标注非遗项目位置?
解答:
在鸿蒙平台上,可以使用模拟的方式实现地图标注:
class MapMarker {
final String id;
final String name;
final double latitude;
final double longitude;
final String type;
MapMarker({
required this.id,
required this.name,
required this.latitude,
required this.longitude,
required this.type,
});
}
class SimpleMapView extends StatelessWidget {
final List<MapMarker> markers;
const SimpleMapView({super.key, required this.markers});
Widget build(BuildContext context) {
return Container(
color: Colors.grey[200],
child: Stack(
children: markers.map((marker) {
// 将经纬度转换为屏幕坐标(简化版)
final x = (marker.longitude - 70) * 10;
final y = (marker.latitude - 15) * 10;
return Positioned(
left: x,
top: y,
child: GestureDetector(
onTap: () {
// 显示标注详情
},
child: Icon(
Icons.location_on,
color: Colors.red,
size: 32,
),
),
);
}).toList(),
),
);
}
}
实现要点:
- 使用Stack布局标注
- Positioned定位标注位置
- GestureDetector处理点击
- 坐标转换算法
3. 如何优化大量数据的加载?
问题:当非遗项目数量很多时,如何优化加载性能?
解答:
可以采用以下优化策略:
- 分页加载:
class PaginatedList extends StatefulWidget {
State<PaginatedList> createState() => _PaginatedListState();
}
class _PaginatedListState extends State<PaginatedList> {
final List<HeritageProject> _displayedProjects = [];
int _currentPage = 0;
final int _pageSize = 20;
bool _isLoading = false;
void initState() {
super.initState();
_loadMore();
}
void _loadMore() {
if (_isLoading) return;
setState(() {
_isLoading = true;
});
// 模拟加载延迟
Future.delayed(const Duration(milliseconds: 500), () {
final start = _currentPage * _pageSize;
final end = start + _pageSize;
final newProjects = _allProjects.sublist(
start,
end > _allProjects.length ? _allProjects.length : end,
);
setState(() {
_displayedProjects.addAll(newProjects);
_currentPage++;
_isLoading = false;
});
});
}
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _displayedProjects.length + 1,
itemBuilder: (context, index) {
if (index == _displayedProjects.length) {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
} else if (_displayedProjects.length < _allProjects.length) {
return TextButton(
onPressed: _loadMore,
child: const Text('加载更多'),
);
} else {
return const Center(child: Text('没有更多了'));
}
}
return _buildProjectCard(_displayedProjects[index]);
},
);
}
}
-
虚拟滚动:
- 使用ListView.builder
- 只渲染可见区域
- 自动回收不可见项
-
数据缓存:
- 缓存筛选结果
- 缓存图片资源
- 使用内存缓存
-
懒加载:
- 延迟加载详情
- 按需加载图片
- 预加载下一页
4. 如何实现离线功能?
问题:如何让应用支持离线查看?
解答:
实现离线功能的关键是数据持久化:
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class OfflineDataManager {
static const String _projectsKey = 'cached_projects';
static const String _inheritorsKey = 'cached_inheritors';
// 保存项目数据
Future<void> saveProjects(List<HeritageProject> projects) async {
final prefs = await SharedPreferences.getInstance();
final jsonList = projects.map((p) => p.toJson()).toList();
await prefs.setString(_projectsKey, jsonEncode(jsonList));
}
// 加载项目数据
Future<List<HeritageProject>> loadProjects() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString(_projectsKey);
if (jsonString == null) return [];
final jsonList = jsonDecode(jsonString) as List;
return jsonList.map((json) => HeritageProject.fromJson(json)).toList();
}
// 保存传承人数据
Future<void> saveInheritors(List<Inheritor> inheritors) async {
final prefs = await SharedPreferences.getInstance();
final jsonList = inheritors.map((i) => i.toJson()).toList();
await prefs.setString(_inheritorsKey, jsonEncode(jsonList));
}
// 加载传承人数据
Future<List<Inheritor>> loadInheritors() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString(_inheritorsKey);
if (jsonString == null) return [];
final jsonList = jsonDecode(jsonString) as List;
return jsonList.map((json) => Inheritor.fromJson(json)).toList();
}
// 检查是否有缓存数据
Future<bool> hasCachedData() async {
final prefs = await SharedPreferences.getInstance();
return prefs.containsKey(_projectsKey);
}
// 清除缓存
Future<void> clearCache() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_projectsKey);
await prefs.remove(_inheritorsKey);
}
}
离线策略:
- 首次加载时缓存数据
- 定期更新缓存
- 离线时使用缓存
- 提示数据更新时间
5. 如何添加多语言支持?
问题:如何让应用支持多语言?
解答:
可以使用Flutter的国际化功能:
// 1. 定义语言资源
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
static final Map<String, Map<String, String>> _localizedValues = {
'zh': {
'app_title': '非遗文化查询',
'projects': '非遗项目',
'inheritors': '传承人',
'map': '地域分布',
'search_hint': '搜索非遗项目、传承人或地区',
'filter': '筛选',
'category': '分类',
'level': '等级',
'province': '省份',
},
'en': {
'app_title': 'Intangible Cultural Heritage',
'projects': 'Projects',
'inheritors': 'Inheritors',
'map': 'Distribution',
'search_hint': 'Search projects, inheritors or regions',
'filter': 'Filter',
'category': 'Category',
'level': 'Level',
'province': 'Province',
},
};
String get appTitle => _localizedValues[locale.languageCode]!['app_title']!;
String get projects => _localizedValues[locale.languageCode]!['projects']!;
String get inheritors => _localizedValues[locale.languageCode]!['inheritors']!;
// ... 更多翻译
}
// 2. 在MaterialApp中配置
MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('zh', 'CN'),
const Locale('en', 'US'),
],
// ...
)
// 3. 使用翻译
Text(AppLocalizations.of(context).appTitle)
多语言支持要点:
- 提取所有文本为资源
- 支持主要语言
- 考虑文本长度变化
- 测试不同语言显示
项目总结
核心功能流程
数据流转
技术架构
项目特色
- 丰富的数据展示:50个非遗项目,30位传承人,涵盖10大分类
- 智能搜索筛选:支持关键词搜索和多维度筛选
- 详细信息展示:项目简介、历史渊源、特色、传承人档案
- 地域分布统计:可视化展示各省份非遗项目分布
- 等级标识清晰:国家级、省级、市级、县级四个等级
- 传承状态标注:传承良好、濒危状态一目了然
- 用户体验优秀:Material Design 3设计,交互流畅
- 无需额外依赖:纯Flutter实现,无需第三方包
学习收获
通过本项目,你将掌握:
- Flutter基础:Widget组合、状态管理、页面导航
- NavigationBar:Material Design 3底部导航使用
- 数据模型:复杂数据结构设计和计算属性
- 集合操作:筛选、排序、统计等List操作
- 搜索功能:实时搜索和多条件筛选实现
- 对话框:ModalBottomSheet和DropdownButton使用
- 卡片布局:Card和InkWell组合使用
- 渐变背景:LinearGradient创建渐变效果
- 数据可视化:LinearProgressIndicator展示统计数据
- UI设计:颜色搭配、图标使用、布局设计
性能优化建议
-
列表优化:
- 使用ListView.builder实现懒加载
- 避免在itemBuilder中创建复杂对象
- 合理使用Key优化列表性能
-
搜索优化:
- 添加防抖功能,避免频繁筛选
- 缓存筛选结果
- 异步处理大量数据
-
状态管理:
- 合理使用setState,避免不必要的重建
- 拆分Widget减少重建范围
- 使用const构造函数
-
内存管理:
- 及时释放不用的资源
- 避免内存泄漏
- 合理使用缓存
-
渲染优化:
- 减少Widget嵌套层级
- 避免在build中执行耗时操作
- 使用RepaintBoundary隔离重绘
后续优化方向
- 真实数据:接入真实的非遗数据API
- 地图功能:在地图上标注项目和传承人位置
- 多媒体:添加视频和图片展示
- 学习功能:提供在线课程和教程
- 活动信息:展示非遗相关活动和展览
- 收藏关注:支持收藏项目和关注传承人
- 社交互动:添加评论、点赞、分享功能
- 数据分析:提供更详细的统计分析
- 离线功能:支持离线查看缓存数据
- 多语言:支持中英文等多语言
文化价值
本项目不仅是一个技术实践,更是对中华优秀传统文化的传承和弘扬:
- 文化传播:让更多人了解非遗文化
- 保护意识:提高非遗保护意识
- 传承推广:促进非遗技艺传承
- 教育价值:作为文化教育工具
- 社会意义:推动文化自信建设
开发建议
- 循序渐进:从基础功能开始,逐步完善
- 注重体验:关注用户体验和交互设计
- 代码规范:保持代码整洁和可维护性
- 测试验证:充分测试各项功能
- 持续优化:根据反馈不断改进
项目亮点
- 教育意义:传播非遗文化知识
- 技术实践:Flutter开发完整实践
- 设计美观:Material Design 3设计
- 功能完整:查询、筛选、统计、详情
- 易于扩展:良好的代码结构
- 无需依赖:纯Flutter实现
- 性能优秀:流畅的用户体验
- 文化价值:弘扬传统文化
本项目提供了一个完整的非遗文化查询应用框架,涵盖了项目查询、传承人信息、地域分布统计等核心功能。你可以在此基础上继续扩展,打造更加专业的非遗文化传播平台,为中华优秀传统文化的保护和传承贡献力量。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)