Flutter框架跨平台鸿蒙开发——演讲稿生成器APP的开发流程

🚀运行效果展示


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(),
      },
    );
  }
}

开发流程详解

  1. 功能需求分析:确定应用的核心功能和用户交互流程
  2. 项目结构设计:设计清晰的项目目录结构,便于代码组织和维护
  3. 数据模型设计:定义应用所需的数据结构,如演讲稿模型
  4. 业务逻辑实现:实现核心功能逻辑,如演讲稿生成算法
  5. 前端布局设计:设计用户友好的界面布局,确保良好的用户体验
  6. 路由配置:设置应用的导航系统,实现页面之间的跳转
  7. 测试与调试:测试应用功能,修复编译错误和运行时异常
  8. 跨平台适配:确保应用在不同平台上的表现一致
  9. 应用构建:构建最终的应用包,准备发布

总结

通过本文的详细介绍,我们完成了基于Flutter框架的演讲稿生成器APP的开发。这款应用不仅实现了演讲稿的智能生成、编辑和管理等核心功能,还通过跨平台技术适配了鸿蒙系统,为用户提供了便捷、高效的演讲准备工具。

项目亮点

  1. 模块化设计:采用清晰的模块化结构,将数据模型、业务逻辑和前端布局分离,提高了代码的可维护性
  2. 智能生成:根据用户输入的参数,生成不同风格和长度的演讲稿内容
  3. 响应式布局:使用Flutter的响应式布局技术,确保应用在不同屏幕尺寸上的良好显示效果
  4. 用户友好:设计简洁明了的用户界面,提供直观的操作流程
  5. 跨平台适配:通过Flutter框架,实现了一次编写,多处运行的目标,成功适配鸿蒙系统

技术栈

  • Flutter:Google开源的UI工具包,用于构建跨平台应用
  • Dart:Flutter的官方编程语言,提供了现代化的语法特性
  • Material Design:采用Material Design设计语言,提供统一的视觉体验

未来展望

在未来的版本中,我们可以考虑以下功能的增强:

  1. 接入AI API:集成更智能的AI模型,提高演讲稿的质量和个性化程度
  2. 语音合成:添加语音合成功能,让用户可以直接听演讲效果
  3. 云同步:实现演讲稿的云端存储和同步,方便用户在不同设备上访问
  4. 模板库:提供多种演讲模板,满足不同场景的需求
  5. 分享功能:支持将演讲稿分享到社交媒体或导出为其他格式

通过不断的功能迭代和技术优化,演讲稿生成器APP将成为用户准备演讲的得力助手,为更多人提供便捷、高效的演讲准备体验。

📚 参考资料

结语

Flutter作为一款优秀的跨平台开发框架,为移动应用开发带来了新的可能性。通过本文的实践,我们不仅掌握了Flutter的基本开发流程,还体验了其在鸿蒙系统上的良好表现。相信随着Flutter生态的不断完善,越来越多的开发者将选择Flutter作为跨平台开发的首选方案,创造出更多优秀的移动应用。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
雨季6661 小时前
Flutter 三端应用实战:OpenHarmony 简易数字累加器开发指南
开发语言·flutter·ui·ecmascript
2601_949720261 小时前
flutter_for_openharmony手语学习app实战+手语识别实现
学习·flutter
●VON2 小时前
Flutter for OpenHarmony:基于 SharedPreferences 的本地化笔记应用架构与实现
笔记·学习·flutter·ui·架构·openharmony·von
程序员清洒2 小时前
Flutter for OpenHarmony:Dialog 与 BottomSheet — 弹出式交互
开发语言·flutter·华为·交互·鸿蒙
ujainu2 小时前
Flutter + OpenHarmony开发端组件实战
flutter
2601_949575862 小时前
Flutter for OpenHarmony艺考真题题库+个人信息管理实现
java·前端·flutter
BlackWolfSky2 小时前
鸿蒙中级课程笔记4—应用程序框架进阶2—Stage模型应用程序包结构、应用间跳转、HSP、HAR
华为·harmonyos
以太浮标2 小时前
华为eNSP模拟器综合实验之- 通过流策略实现Vlan内二/三层隔离
网络·网络协议·华为
心态还需努力呀2 小时前
【鸿蒙PC命令行适配】GNU Hello 库在鸿蒙 PC 上的交叉编译与移植部署实战
华为·鸿蒙·gnu·openharmony·开源鸿蒙