🚀运行效果展示


Flutter框架跨平台鸿蒙开发------演讲稿生成器APP的开发流程
前言
随着移动互联网的快速发展,跨平台开发框架已经成为移动应用开发的重要趋势。Flutter作为Google推出的开源UI工具包,以其"一次编写,多处运行"的特性,为开发者提供了高效、便捷的跨平台开发解决方案。本文将详细介绍基于Flutter框架开发的演讲稿生成器APP的完整开发流程,包括功能分析、核心逻辑实现、前端布局设计以及跨平台鸿蒙适配等内容,旨在为Flutter初学者和有经验的开发者提供参考。
应用介绍
演讲稿生成器APP是一款专为需要准备演讲的用户设计的工具型应用,它能够根据用户输入的主题、时长、风格和目标受众等参数,自动生成结构化的演讲稿内容。用户可以在生成后对内容进行编辑和保存,并查看历史生成记录。
核心功能
- 主题输入:用户可以输入演讲的核心主题
- 时长设置:用户可以设置演讲的预计时长(分钟)
- 风格选择:提供正式、轻松、激励、学术四种演讲风格
- 受众选择:提供听众、学生、员工、客户、领导五种目标受众
- 智能生成:根据用户输入的参数自动生成演讲稿内容
- 编辑保存:用户可以对生成的演讲稿进行编辑和保存
- 历史记录:查看和管理已保存的演讲稿
核心功能实现及代码展示
1. 项目结构设计
在开始编码之前,我们首先需要设计清晰的项目结构,以便于后续的开发和维护。
lib/
├── models/ # 数据模型
│ └── speech_model.dart # 演讲稿模型
├── services/ # 业务逻辑
│ └── speech_service.dart # 演讲稿服务
├── screens/ # 页面
│ ├── speech_generator_screen.dart # 演讲稿生成页面
│ ├── speech_editor_screen.dart # 演讲稿编辑页面
│ └── speech_history_screen.dart # 演讲稿历史记录页面
└── main.dart # 应用入口
2. 数据模型设计
首先,我们需要设计演讲稿的数据模型,用于存储演讲稿的相关信息。
speech_model.dart
dart
/// 演讲稿模型类
/// 用于存储演讲稿的相关信息
class SpeechModel {
/// 演讲稿ID
final String id;
/// 演讲稿主题
final String topic;
/// 演讲时长(分钟)
final int duration;
/// 演讲风格
final String style;
/// 目标受众
final String audience;
/// 演讲稿内容
final String content;
/// 创建时间
final DateTime createdAt;
/// 最后修改时间
DateTime updatedAt;
/// 构造函数
SpeechModel({
required this.id,
required this.topic,
required this.duration,
required this.style,
required this.audience,
required this.content,
required this.createdAt,
required this.updatedAt,
});
/// 从JSON转换为SpeechModel
factory SpeechModel.fromJson(Map<String, dynamic> json) {
return SpeechModel(
id: json['id'],
topic: json['topic'],
duration: json['duration'],
style: json['style'],
audience: json['audience'],
content: json['content'],
createdAt: DateTime.parse(json['createdAt']),
updatedAt: DateTime.parse(json['updatedAt']),
);
}
/// 转换为JSON
Map<String, dynamic> toJson() {
return {
'id': id,
'topic': topic,
'duration': duration,
'style': style,
'audience': audience,
'content': content,
'createdAt': createdAt.toIso8601String(),
'updatedAt': updatedAt.toIso8601String(),
};
}
/// 创建一个新的SpeechModel实例,更新特定字段
SpeechModel copyWith({
String? id,
String? topic,
int? duration,
String? style,
String? audience,
String? content,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return SpeechModel(
id: id ?? this.id,
topic: topic ?? this.topic,
duration: duration ?? this.duration,
style: style ?? this.style,
audience: audience ?? this.audience,
content: content ?? this.content,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
}
3. 业务逻辑实现
接下来,我们实现演讲稿生成的核心业务逻辑,包括生成不同风格的演讲稿内容、保存和加载历史记录等功能。
speech_service.dart
dart
/// 演讲稿服务类
/// 用于处理演讲稿的生成、保存、加载等操作
import 'dart:math';
import '../models/speech_model.dart';
class SpeechService {
/// 生成演讲稿
/// [topic] 演讲主题
/// [duration] 演讲时长(分钟)
/// [style] 演讲风格
/// [audience] 目标受众
/// 返回生成的演讲稿内容
Future<String> generateSpeech({
required String topic,
required int duration,
required String style,
required String audience,
}) async {
// 模拟生成演讲稿内容
// 实际项目中可以接入AI API进行智能生成
await Future.delayed(Duration(seconds: 2)); // 模拟网络延迟
// 根据参数生成不同风格的演讲稿
String content = '';
// 开场白
content += _generateOpening(topic, style, audience);
// 主体内容(根据时长生成不同长度)
int paragraphs = max(2, duration ~/ 2); // 每2分钟一个段落
for (int i = 0; i < paragraphs; i++) {
content += _generateBody(topic, style, i + 1, paragraphs);
}
// 结束语
content += _generateClosing(topic, style, audience);
return content;
}
/// 生成开场白
String _generateOpening(String topic, String style, String audience) {
List<String> openings = [];
switch (style) {
case '正式':
openings = [
'尊敬的各位${audience},大家好!今天我非常荣幸能够站在这里,和大家分享关于"${topic}"的一些思考。',
'各位${audience},上午好!很高兴今天有机会和大家探讨"${topic}"这个重要话题。',
'尊敬的${audience},大家好!今天我想和大家聊一聊"${topic}",这是一个值得我们深入思考的问题。',
];
break;
case '轻松':
openings = [
'嘿,各位${audience}!大家好啊!今天咱们来聊聊"${topic}",这事儿可有意思了。',
'大家好!我是今天的分享者,很高兴能和各位${audience}一起聊聊"${topic}"这个话题。',
'哈喽,各位${audience}!今天天气不错,咱们来聊聊"${topic}",希望能给大家带来一些启发。',
];
break;
case '激励':
openings = [
'各位${audience},当我想到"${topic}"这个话题时,我的内心充满了激情和动力!',
'尊敬的${audience},今天我要和大家分享的"${topic}",是一个能够改变我们生活的重要理念!',
'亲爱的${audience},我相信"${topic}"将会成为我们未来发展的关键,让我们一起探索它的无限可能!',
];
break;
case '学术':
openings = [
'尊敬的${audience},今天我将从学术角度探讨"${topic}"这一领域的最新研究进展。',
'各位${audience},感谢大家的到来。今天我要分享的是关于"${topic}"的一些学术思考。',
'尊敬的${audience},"${topic}"是当前学术界关注的热点问题,今天我将对此进行深入分析。',
];
break;
default:
openings = [
'各位${audience},大家好!今天我要和大家分享的话题是"${topic}"。',
'尊敬的${audience},很高兴见到大家。今天我们来聊聊"${topic}"。',
'大家好!我是今天的演讲者,今天的话题是"${topic}"。',
];
}
return openings[Random().nextInt(openings.length)] + '\n\n';
}
/// 生成主体内容
String _generateBody(String topic, String style, int current, int total) {
List<String> bodies = [];
switch (style) {
case '正式':
bodies = [
'首先,让我们来了解一下"${topic}"的基本概念。${topic}是指...',
'接下来,我想和大家分享一下${topic}的重要性。它对我们的生活和工作有着深远的影响...',
'从历史发展的角度来看,${topic}经历了漫长的演变过程...',
'在当今社会,${topic}面临着诸多挑战和机遇...',
'根据最新的研究数据,我们可以看到${topic}的发展趋势...',
];
break;
case '轻松':
bodies = [
'咱们先来说说${topic}是怎么回事儿。简单来说啊,${topic}就是...',
'接下来聊聊${topic}的重要性。你可别小看它,它对咱们的日常生活影响可大了...',
'从过去到现在,${topic}可是发生了翻天覆地的变化...',
'现在咱们面临的情况是,${topic}既有好的一面,也有需要改进的地方...',
'我最近看到一些数据,特别有意思,说的是${topic}的发展情况...',
];
break;
case '激励':
bodies = [
'首先,我要告诉大家,${topic}是我们实现梦想的关键!它能够帮助我们...',
'接下来,让我们一起探索${topic}的无限潜力。只要我们勇敢尝试,就能够...',
'回顾历史,那些成功的人都是因为重视${topic}才取得了辉煌的成就...',
'朋友们,现在正是我们拥抱${topic}的最佳时机!让我们携手共进,创造美好的未来...',
'我相信,只要我们坚持努力,${topic}一定会给我们带来意想不到的收获...',
];
break;
case '学术':
bodies = [
'首先,我们需要对${topic}进行明确的概念界定。根据XXX的研究,${topic}可以定义为...',
'接下来,本文将从理论框架的角度分析${topic}的内在机制...',
'通过对相关文献的梳理,我们可以发现${topic}的研究主要集中在以下几个方面...',
'本研究采用了XXX方法,对${topic}进行了实证分析...',
'研究结果表明,${topic}与XXX之间存在显著的相关性...',
];
break;
default:
bodies = [
'首先,让我们来了解一下${topic}的基本情况...',
'接下来,我想和大家分享一下${topic}的重要性...',
'从不同的角度来看,${topic}有着不同的意义...',
'在实际应用中,${topic}可以帮助我们解决很多问题...',
'未来,${topic}的发展前景非常广阔...',
];
}
String body = bodies[Random().nextInt(bodies.length)];
// 添加一些具体内容
body += ' 这是第${current}部分内容,我们需要深入理解${topic}的内涵,'
'探索其在不同场景下的应用,以及如何更好地发挥其价值。';
return body + '\n\n';
}
/// 生成结束语
String _generateClosing(String topic, String style, String audience) {
List<String> closings = [];
switch (style) {
case '正式':
closings = [
'综上所述,${topic}是一个值得我们持续关注和深入研究的重要话题。希望我的分享能够给大家带来一些启发,谢谢大家!',
'最后,我想说的是,${topic}的发展需要我们每个人的共同努力。让我们携手共进,为${topic}的美好未来而奋斗!谢谢大家!',
'以上就是我关于"${topic}"的一些思考和见解,不足之处还请各位${audience}批评指正。谢谢大家的聆听!',
];
break;
case '轻松':
closings = [
'好啦,今天关于${topic}的分享就到这里啦!希望大家听了之后能有所收获,咱们下次再见!',
'总之呢,${topic}其实挺有意思的,对吧?希望我的分享能让大家对它有更多的了解,谢谢大家!',
'最后想说的是,${topic}和我们的生活息息相关,希望大家以后能多关注它。谢谢各位${audience}的捧场!',
];
break;
case '激励':
closings = [
'朋友们,让我们从现在开始,行动起来,拥抱${topic},创造属于我们的精彩人生!谢谢大家!',
'最后,我想用一句话来总结今天的分享:${topic},让我们的未来更加美好!谢谢大家的热情参与!',
'相信在不久的将来,${topic}一定会给我们的生活带来巨大的改变。让我们拭目以待,共同见证这一伟大的时刻!谢谢大家!',
];
break;
case '学术':
closings = [
'综上所述,本研究通过对${topic}的深入分析,得出了以下结论...',
'最后,需要指出的是,${topic}的研究还有许多待探索的领域,希望未来有更多的学者关注这一方向...',
'以上就是我关于${topic}的学术分享,感谢各位${audience}的聆听和宝贵意见。',
];
break;
default:
closings = [
'总之,${topic}是一个非常重要的话题。希望我的分享能够对大家有所帮助,谢谢大家!',
'最后,感谢大家的聆听。关于${topic},我们还有很多需要学习和探索的地方,让我们一起努力!',
'以上就是我今天要分享的内容,希望大家对${topic}有了更深入的了解。谢谢大家!',
];
}
return closings[Random().nextInt(closings.length)];
}
/// 保存演讲稿到本地存储
/// [speech] 演讲稿对象
Future<void> saveSpeech(SpeechModel speech) async {
// 实际项目中可以使用shared_preferences或sqflite进行本地存储
// 这里仅做模拟
print('保存演讲稿: ${speech.topic}');
}
/// 加载历史演讲稿
/// 返回演讲稿列表
Future<List<SpeechModel>> loadHistorySpeeches() async {
// 模拟加载历史演讲稿
await Future.delayed(Duration(seconds: 1));
// 返回一些模拟数据
return [
SpeechModel(
id: '1',
topic: '环境保护的重要性',
duration: 5,
style: '正式',
audience: '听众',
content: '尊敬的各位听众,大家好!今天我非常荣幸能够站在这里,和大家分享关于"环境保护的重要性"的一些思考。...',
createdAt: DateTime.now().subtract(Duration(days: 2)),
updatedAt: DateTime.now().subtract(Duration(days: 2)),
),
SpeechModel(
id: '2',
topic: '如何提高学习效率',
duration: 8,
style: '轻松',
audience: '学生',
content: '嘿,各位学生!大家好啊!今天咱们来聊聊"如何提高学习效率",这事儿可有意思了。...',
createdAt: DateTime.now().subtract(Duration(days: 5)),
updatedAt: DateTime.now().subtract(Duration(days: 4)),
),
];
}
/// 删除演讲稿
/// [id] 演讲稿ID
Future<void> deleteSpeech(String id) async {
// 模拟删除演讲稿
await Future.delayed(Duration(seconds: 1));
print('删除演讲稿: $id');
}
}
4. 前端布局实现
4.1 演讲稿生成页面
dart
/// 演讲稿生成页面
/// 用于输入演讲主题、时长、风格和目标受众等参数
import 'package:flutter/material.dart';
import '../services/speech_service.dart';
import '../models/speech_model.dart';
import 'speech_editor_screen.dart';
class SpeechGeneratorScreen extends StatefulWidget {
/// 构造函数
const SpeechGeneratorScreen({Key? key}) : super(key: key);
@override
_SpeechGeneratorScreenState createState() => _SpeechGeneratorScreenState();
}
class _SpeechGeneratorScreenState extends State<SpeechGeneratorScreen> {
/// 演讲主题控制器
final _topicController = TextEditingController();
/// 演讲时长控制器
final _durationController = TextEditingController(text: '5');
/// 演讲风格选项
final List<String> _styleOptions = ['正式', '轻松', '激励', '学术'];
/// 目标受众选项
final List<String> _audienceOptions = ['听众', '学生', '员工', '客户', '领导'];
/// 选中的演讲风格
String _selectedStyle = '正式';
/// 选中的目标受众
String _selectedAudience = '听众';
/// 是否正在生成演讲稿
bool _isGenerating = false;
/// 演讲稿服务
final _speechService = SpeechService();
@override
void dispose() {
_topicController.dispose();
_durationController.dispose();
super.dispose();
}
/// 生成演讲稿
Future<void> _generateSpeech() async {
// 验证输入
if (_topicController.text.isEmpty) {
_showSnackBar('请输入演讲主题');
return;
}
if (_durationController.text.isEmpty) {
_showSnackBar('请输入演讲时长');
return;
}
int duration = int.tryParse(_durationController.text) ?? 0;
if (duration <= 0) {
_showSnackBar('请输入有效的演讲时长');
return;
}
// 开始生成演讲稿
setState(() {
_isGenerating = true;
});
try {
// 生成演讲稿内容
String content = await _speechService.generateSpeech(
topic: _topicController.text,
duration: duration,
style: _selectedStyle,
audience: _selectedAudience,
);
// 创建演讲稿对象
SpeechModel speech = SpeechModel(
id: DateTime.now().millisecondsSinceEpoch.toString(),
topic: _topicController.text,
duration: duration,
style: _selectedStyle,
audience: _selectedAudience,
content: content,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
// 跳转到编辑页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SpeechEditorScreen(speech: speech),
),
);
} catch (e) {
_showSnackBar('生成演讲稿失败,请重试');
print('生成演讲稿失败: $e');
} finally {
setState(() {
_isGenerating = false;
});
}
}
/// 显示提示信息
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('演讲稿生成器'),
actions: [
IconButton(
icon: const Icon(Icons.history),
onPressed: () {
Navigator.pushNamed(context, '/speech_history');
},
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 演讲主题输入
_buildTextField(
controller: _topicController,
labelText: '演讲主题',
hintText: '请输入演讲主题',
maxLines: 2,
),
const SizedBox(height: 16),
// 演讲时长输入
_buildTextField(
controller: _durationController,
labelText: '演讲时长(分钟)',
hintText: '请输入演讲时长',
keyboardType: TextInputType.number,
),
const SizedBox(height: 16),
// 演讲风格选择
_buildDropdownField(
labelText: '演讲风格',
value: _selectedStyle,
items: _styleOptions,
onChanged: (value) {
setState(() {
_selectedStyle = value!;
});
},
),
const SizedBox(height: 16),
// 目标受众选择
_buildDropdownField(
labelText: '目标受众',
value: _selectedAudience,
items: _audienceOptions,
onChanged: (value) {
setState(() {
_selectedAudience = value!;
});
},
),
const SizedBox(height: 32),
// 生成按钮
ElevatedButton(
onPressed: _isGenerating ? null : _generateSpeech,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
textStyle: const TextStyle(fontSize: 18),
),
child: _isGenerating
? const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
SizedBox(width: 16),
Text('生成中...'),
],
)
: const Text('生成演讲稿'),
),
],
),
),
);
}
/// 构建文本输入框
Widget _buildTextField({
required TextEditingController controller,
required String labelText,
required String hintText,
TextInputType keyboardType = TextInputType.text,
int maxLines = 1,
}) {
return TextField(
controller: controller,
keyboardType: keyboardType,
maxLines: maxLines,
decoration: InputDecoration(
labelText: labelText,
hintText: hintText,
border: const OutlineInputBorder(),
filled: true,
fillColor: Colors.grey[50],
),
);
}
/// 构建下拉选择框
Widget _buildDropdownField({
required String labelText,
required String value,
required List<String> items,
required ValueChanged<String?> onChanged,
}) {
return DropdownButtonFormField<String>(
value: value,
items: items.map((item) {
return DropdownMenuItem<String>(
value: item,
child: Text(item),
);
}).toList(),
onChanged: onChanged,
decoration: InputDecoration(
labelText: labelText,
border: const OutlineInputBorder(),
filled: true,
fillColor: Colors.grey[50],
),
);
}
}
4.2 演讲稿编辑页面
dart
/// 演讲稿编辑页面
/// 用于编辑和保存生成的演讲稿
import 'package:flutter/material.dart';
import '../models/speech_model.dart';
import '../services/speech_service.dart';
class SpeechEditorScreen extends StatefulWidget {
/// 演讲稿对象
final SpeechModel speech;
/// 构造函数
const SpeechEditorScreen({Key? key, required this.speech}) : super(key: key);
@override
_SpeechEditorScreenState createState() => _SpeechEditorScreenState();
}
class _SpeechEditorScreenState extends State<SpeechEditorScreen> {
/// 演讲稿主题控制器
late TextEditingController _topicController;
/// 演讲稿内容控制器
late TextEditingController _contentController;
/// 是否正在保存
bool _isSaving = false;
/// 演讲稿服务
final _speechService = SpeechService();
@override
void initState() {
super.initState();
// 初始化控制器
_topicController = TextEditingController(text: widget.speech.topic);
_contentController = TextEditingController(text: widget.speech.content);
}
@override
void dispose() {
_topicController.dispose();
_contentController.dispose();
super.dispose();
}
/// 保存演讲稿
Future<void> _saveSpeech() async {
// 开始保存
setState(() {
_isSaving = true;
});
try {
// 更新演讲稿对象
SpeechModel updatedSpeech = widget.speech.copyWith(
topic: _topicController.text,
content: _contentController.text,
updatedAt: DateTime.now(),
);
// 保存演讲稿
await _speechService.saveSpeech(updatedSpeech);
// 显示保存成功提示
_showSnackBar('保存成功');
// 返回上一页
Navigator.pop(context);
} catch (e) {
_showSnackBar('保存失败,请重试');
print('保存演讲稿失败: $e');
} finally {
setState(() {
_isSaving = false;
});
}
}
/// 显示提示信息
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('编辑演讲稿'),
actions: [
IconButton(
icon: _isSaving
? const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
)
: const Icon(Icons.save),
onPressed: _isSaving ? null : _saveSpeech,
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 演讲主题输入
TextField(
controller: _topicController,
decoration: InputDecoration(
labelText: '演讲主题',
border: const OutlineInputBorder(),
filled: true,
fillColor: Colors.grey[50],
),
),
const SizedBox(height: 16),
// 演讲信息展示
Card(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('演讲时长: ${widget.speech.duration}分钟'),
Text('演讲风格: ${widget.speech.style}'),
],
),
const SizedBox(height: 8),
Text('目标受众: ${widget.speech.audience}'),
const SizedBox(height: 8),
Text('创建时间: ${widget.speech.createdAt.toString().substring(0, 19)}'),
],
),
),
),
const SizedBox(height: 16),
// 演讲稿内容编辑
TextField(
controller: _contentController,
maxLines: null, // 无限行数
decoration: InputDecoration(
labelText: '演讲稿内容',
border: const OutlineInputBorder(),
filled: true,
fillColor: Colors.grey[50],
),
),
const SizedBox(height: 32),
],
),
),
);
}
}
4.3 演讲稿历史记录页面
dart
/// 演讲稿历史记录页面
/// 用于展示和管理已保存的演讲稿
import 'package:flutter/material.dart';
import '../models/speech_model.dart';
import '../services/speech_service.dart';
import 'speech_editor_screen.dart';
class SpeechHistoryScreen extends StatefulWidget {
/// 构造函数
const SpeechHistoryScreen({Key? key}) : super(key: key);
@override
_SpeechHistoryScreenState createState() => _SpeechHistoryScreenState();
}
class _SpeechHistoryScreenState extends State<SpeechHistoryScreen> {
/// 演讲稿列表
List<SpeechModel> _speeches = [];
/// 是否正在加载
bool _isLoading = true;
/// 演讲稿服务
final _speechService = SpeechService();
@override
void initState() {
super.initState();
// 加载历史演讲稿
_loadHistorySpeeches();
}
/// 加载历史演讲稿
Future<void> _loadHistorySpeeches() async {
try {
List<SpeechModel> speeches = await _speechService.loadHistorySpeeches();
setState(() {
_speeches = speeches;
_isLoading = false;
});
} catch (e) {
print('加载历史演讲稿失败: $e');
setState(() {
_isLoading = false;
});
}
}
/// 删除演讲稿
Future<void> _deleteSpeech(String id) async {
// 显示确认对话框
bool? confirmed = await showDialog<bool>(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('确认删除'),
content: const Text('确定要删除这篇演讲稿吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('取消'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('删除'),
),
],
);
},
);
if (confirmed == true) {
try {
// 删除演讲稿
await _speechService.deleteSpeech(id);
// 更新列表
setState(() {
_speeches.removeWhere((speech) => speech.id == id);
});
// 显示删除成功提示
_showSnackBar('删除成功');
} catch (e) {
_showSnackBar('删除失败,请重试');
print('删除演讲稿失败: $e');
}
}
}
/// 编辑演讲稿
void _editSpeech(SpeechModel speech) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SpeechEditorScreen(speech: speech),
),
).then((_) {
// 编辑完成后重新加载列表
_loadHistorySpeeches();
});
}
/// 显示提示信息
void _showSnackBar(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('历史演讲稿'),
),
body: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
: _speeches.isEmpty
? const Center(
child: Text('暂无历史演讲稿'),
)
: ListView.builder(
itemCount: _speeches.length,
itemBuilder: (context, index) {
SpeechModel speech = _speeches[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
title: Text(
speech.topic,
style: const TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 4),
Text('${speech.duration}分钟 | ${speech.style} | ${speech.audience}'),
const SizedBox(height: 4),
Text(
speech.content.length > 100
? '${speech.content.substring(0, 100)}...'
: speech.content,
style: TextStyle(color: Colors.grey[600], fontSize: 14),
),
const SizedBox(height: 4),
Text(
'更新时间: ${speech.updatedAt.toString().substring(0, 19)}',
style: TextStyle(color: Colors.grey[500], fontSize: 12),
),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () => _editSpeech(speech),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _deleteSpeech(speech.id),
),
],
),
onTap: () => _editSpeech(speech),
),
);
},
),
);
}
}
5. 路由配置
最后,我们需要配置应用的路由系统,以便于页面之间的导航。
main.dart
dart
import 'package:flutter/material.dart';
import 'screens/speech_generator_screen.dart';
import 'screens/speech_history_screen.dart';
/// 演讲稿生成器应用主入口
/// 用于启动演讲稿生成器应用
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const SpeechGeneratorApp());
}
/// 演讲稿生成器应用根组件
class SpeechGeneratorApp extends StatelessWidget {
/// 构造函数
const SpeechGeneratorApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '演讲稿生成器',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
appBarTheme: const AppBarTheme(
backgroundColor: Colors.blue,
elevation: 4,
titleTextStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
),
debugShowCheckedModeBanner: false,
initialRoute: '/',
routes: {
'/': (context) => const SpeechGeneratorScreen(),
'/speech_history': (context) => const SpeechHistoryScreen(),
},
);
}
}
开发流程详解
- 功能需求分析:确定应用的核心功能和用户交互流程
- 项目结构设计:设计清晰的项目目录结构,便于代码组织和维护
- 数据模型设计:定义应用所需的数据结构,如演讲稿模型
- 业务逻辑实现:实现核心功能逻辑,如演讲稿生成算法
- 前端布局设计:设计用户友好的界面布局,确保良好的用户体验
- 路由配置:设置应用的导航系统,实现页面之间的跳转
- 测试与调试:测试应用功能,修复编译错误和运行时异常
- 跨平台适配:确保应用在不同平台上的表现一致
- 应用构建:构建最终的应用包,准备发布
总结
通过本文的详细介绍,我们完成了基于Flutter框架的演讲稿生成器APP的开发。这款应用不仅实现了演讲稿的智能生成、编辑和管理等核心功能,还通过跨平台技术适配了鸿蒙系统,为用户提供了便捷、高效的演讲准备工具。
项目亮点
- 模块化设计:采用清晰的模块化结构,将数据模型、业务逻辑和前端布局分离,提高了代码的可维护性
- 智能生成:根据用户输入的参数,生成不同风格和长度的演讲稿内容
- 响应式布局:使用Flutter的响应式布局技术,确保应用在不同屏幕尺寸上的良好显示效果
- 用户友好:设计简洁明了的用户界面,提供直观的操作流程
- 跨平台适配:通过Flutter框架,实现了一次编写,多处运行的目标,成功适配鸿蒙系统
技术栈
- Flutter:Google开源的UI工具包,用于构建跨平台应用
- Dart:Flutter的官方编程语言,提供了现代化的语法特性
- Material Design:采用Material Design设计语言,提供统一的视觉体验
未来展望
在未来的版本中,我们可以考虑以下功能的增强:
- 接入AI API:集成更智能的AI模型,提高演讲稿的质量和个性化程度
- 语音合成:添加语音合成功能,让用户可以直接听演讲效果
- 云同步:实现演讲稿的云端存储和同步,方便用户在不同设备上访问
- 模板库:提供多种演讲模板,满足不同场景的需求
- 分享功能:支持将演讲稿分享到社交媒体或导出为其他格式
通过不断的功能迭代和技术优化,演讲稿生成器APP将成为用户准备演讲的得力助手,为更多人提供便捷、高效的演讲准备体验。
📚 参考资料
结语
Flutter作为一款优秀的跨平台开发框架,为移动应用开发带来了新的可能性。通过本文的实践,我们不仅掌握了Flutter的基本开发流程,还体验了其在鸿蒙系统上的良好表现。相信随着Flutter生态的不断完善,越来越多的开发者将选择Flutter作为跨平台开发的首选方案,创造出更多优秀的移动应用。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net