Flutter 框架跨平台鸿蒙开发 - 晚安故事生成器
运行效果图晚安故事生成器是一款面向全年龄段用户的创意应用,核心定位在于通过关键词触发,为用户编织独一无二的睡前故事。这款应用不仅是一个内容生成工具,更是一个陪伴用户进入甜美梦境的数字伙伴。应用采用"模板+词库替换"的策略实现故事创作,内置3套故事模板,每套模板包含10+个可替换占位符,理论组合数约2900万种独特故事。晚安故事生成器应用通过"模板+词库替换"的策略,为用户提供个性化的睡前故事创作体
晚安故事生成器应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图






1.1 应用简介
晚安故事生成器是一款面向全年龄段用户的创意应用,核心定位在于通过关键词触发,为用户编织独一无二的睡前故事。这款应用不仅是一个内容生成工具,更是一个陪伴用户进入甜美梦境的数字伙伴。
应用采用"模板+词库替换"的策略实现故事创作,内置3套故事模板,每套模板包含10+个可替换占位符,理论组合数约2900万种独特故事。用户只需输入关键词,即可获得专属的睡前故事,支持收藏管理和历史记录功能。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 故事创作 | 关键词输入、AI生成 | 模板替换算法、随机组合 |
| 故事阅读 | 文本展示、进度跟踪 | CustomScrollView、Sliver |
| 语音朗读 | TTS播放控制 | 模拟播放状态管理 |
| 历史管理 | 本地存储、列表展示 | 内存存储、列表渲染 |
| 收藏系统 | 收藏/取消、分类查看 | 状态同步、筛选过滤 |
| 个性设置 | 朗读参数、生成偏好 | 配置界面、状态持久化 |
1.3 故事生成流程
| 阶段 | 步骤 | 说明 |
|---|---|---|
| 1 | 关键词输入 | 输入或选择关键词 |
| 2 | 模板选择 | 随机选择故事模板 |
| 3 | 占位符替换 | 替换模板中的占位符 |
| 4 | 关键词注入 | 将用户关键词融入故事 |
| 5 | 元数据计算 | 计算阅读时间和字数 |
| 6 | 故事展示 | 展示生成的故事 |
1.4 模板占位符
| 占位符 | 词库示例 | 替换数量 |
|---|---|---|
| {place} | 彩虹谷、星光森林、云朵小镇 | 5个 |
| {character} | 小兔子、小熊、小狐狸 | 5个 |
| {feature} | 毛茸茸、闪闪发光、温暖 | 5个 |
| {time} | 清晨、黄昏、月光下 | 5个 |
| {activity} | 采蘑菇、数星星、收集露珠 | 5个 |
| {object} | 魔法灯、许愿石、时光沙漏 | 5个 |
| {wish} | 每个人都能快乐、世界充满爱 | 5个 |
| {lesson} | 珍惜当下、友谊最珍贵 | 5个 |
| {location} | 水晶花园、梦幻瀑布、彩虹桥 | 5个 |
| {journey} | 翻越高山、穿越森林、渡过河流 | 5个 |
1.5 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design | - |
| 状态管理 | setState | - |
| 动画控制 | AnimationController | - |
| 目标平台 | 鸿蒙OS | API 21+ |
1.6 项目结构
lib/
└── main_bedtime_story.dart
├── BedtimeStoryApp # 应用入口
├── MainScreen # 主屏幕(底部导航)
├── HomePage # 创作页面
├── HistoryPage # 历史记录页面
├── FavoritesPage # 收藏页面
├── SettingsPage # 设置页面
├── StoryCard # 故事卡片组件
├── StoryDetailSheet # 故事详情底部面板
├── StarPainter # 星空绘制器
├── Story # 数据模型
├── StoryGenerator # 故事生成器
└── StoryStorage # 存储管理器
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 故事生成流程
2.4 收藏管理流程
三、核心模块设计
3.1 数据模型设计
3.1.1 故事模型 (Story)
class Story {
final String id; // 唯一标识(时间戳)
final String title; // 故事标题
final String content; // 完整内容
final String preview; // 预览文本(前100字)
final List<String> keywords; // 关键词列表
final String createdAt; // 创建时间(yyyy-MM-dd HH:mm)
final int readingTime; // 预计阅读时间(分钟)
final int wordCount; // 字数统计
bool isFavorite; // 收藏状态
}
3.1.2 故事生成器 (StoryGenerator)
class StoryGenerator {
static final List<String> _templates = [
'从前,在遥远的{place},住着一只可爱的{character}...',
'在{place}的深处,有一片神秘的{location}...',
'{character}住在一个{feature}的小屋里...',
];
static final Map<String, List<String>> _words = {
'place': ['彩虹谷', '星光森林', '云朵小镇', '月亮湖畔', '水晶山洞'],
'character': ['小兔子', '小熊', '小狐狸', '小猫咪', '小松鼠'],
// ... 其他词库
};
static Story generate({required List<String> keywords});
}
3.1.3 存储管理器 (StoryStorage)
class StoryStorage {
static final List<Story> _history = [];
static final List<Story> _favorites = [];
static List<Story> get history => List.unmodifiable(_history);
static List<Story> get favorites => List.unmodifiable(_favorites);
static void addToHistory(Story story) {
_history.insert(0, story);
if (_history.length > 50) {
_history.removeLast();
}
}
static void toggleFavorite(String id);
static void clearHistory();
}
3.2 星空绘制器
3.2.1 绘制原理
3.2.2 实现代码
class StarPainter extends CustomPainter {
final AnimationController controller;
StarPainter(this.controller) : super(repaint: controller);
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = Colors.white;
final random = Random(42);
for (int i = 0; i < 50; i++) {
final x = random.nextDouble() * size.width;
final y = random.nextDouble() * size.height;
final radius = random.nextDouble() * 2 + 0.5;
final opacity = (random.nextDouble() * 0.5 + 0.3) *
(0.7 + controller.value * 0.3);
paint.color = Colors.white.withValues(alpha: opacity);
canvas.drawCircle(Offset(x, y), radius, paint);
}
}
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
3.3 月亮呼吸动画
3.3.1 动画原理
3.3.2 实现代码
AnimatedBuilder(
animation: widget.moonController,
builder: (context, child) {
return Transform.scale(
scale: 1 + widget.moonController.value * 0.05,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: const Color(0xFFFEFCD7),
boxShadow: [
BoxShadow(
color: const Color(0xFFFEFCD7).withValues(alpha: 0.5),
blurRadius: 30 + widget.moonController.value * 10,
spreadRadius: 5,
),
],
),
),
);
},
)
3.4 故事详情面板
3.4.1 面板规格
| 属性 | 值 | 说明 |
|---|---|---|
| initialChildSize | 0.9 | 初始占屏幕90% |
| minChildSize | 0.5 | 最小可拖拽至50% |
| maxChildSize | 0.95 | 最大可展开至95% |
| 圆角 | 24px | 顶部圆角 |
3.4.2 面板结构
3.5 页面结构设计
3.5.1 主页面布局
3.6 状态管理
3.6.1 核心状态变量
class _HomePageState extends State<HomePage> {
final TextEditingController _keywordController = TextEditingController();
bool _isGenerating = false;
Story? _currentStory;
double _generationProgress = 0;
}
class _StoryDetailSheetState extends State<StoryDetailSheet> {
bool _isPlaying = false;
bool _isFavorite = false;
}
四、UI设计规范
4.1 配色方案
应用采用深色主题配合紫色主色调,营造梦幻氛围:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #9C7BB8 | AppBar、强调、按钮 |
| 背景渐变起始 | #1a1a2e | 深邃夜空 |
| 背景渐变中间 | #16213e | 星空过渡 |
| 月亮色 | #FEFCD7 | 温暖月光 |
| 收藏色 | #FF5252 | 醒目红色 |
4.2 字体规范
| 层级 | 字号 | 字重 | 用途 |
|---|---|---|---|
| 标题大字 | headlineMedium | Bold | 页面主标题 |
| 卡片标题 | titleMedium | Bold | 故事标题 |
| 正文 | bodyLarge | Regular | 故事内容 |
| 辅助文字 | bodySmall | Regular | 时间、字数 |
4.3 组件规范
4.3.1 创作页面头部
┌─────────────────────────────────┐
│ ★ ★ 🌙 │ ← 星空背景 + 动态月亮
│ ★ ★ ★ │
│ │
│ 晚安故事 │ ← 主标题
│ 让AI为你编织一个温暖的梦 │ ← 副标题
└─────────────────────────────────┘
4.3.2 关键词输入区
┌─────────────────────────────────┐
│ 关键词 │
│ ┌─────────────────────────┐ │
│ │ 小兔子、星空... ✕ │ │
│ └─────────────────────────┘ │
│ 推荐关键词 │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │+小兔子│+星空│+魔法森林│ │
│ └────┘ └────┘ └────┘ │
└─────────────────────────────────┘
4.3.3 故事卡片
┌─────────────────────────────────┐
│ ┌────┐ 小兔子的奇妙冒险 ♡ │
│ │ 📖 │ 2024-01-15 22:30 │
│ └────┘ │
│ ┌────┐ ┌────┐ │
│ │小兔子│ │星空│ │
│ └────┘ └────┘ │
│ 从前,在遥远的彩虹谷... │
│ ⏱️2分钟 📝356字 │
└─────────────────────────────────┘
4.3.4 故事详情面板
┌─────────────────────────────────┐
│ ━━━ │ ← 拖拽指示条
│ ✕ ♡ ↗ ⋮ │ ← 操作按钮栏
│ │
│ 小兔子的奇妙冒险 │ ← 故事标题
│ ┌────┐ ┌────┐ │
│ │小兔子│ │星空│ │ ← 关键词标签
│ └────┘ └────┘ │
│ ⏱️阅读约2分钟 📝356字 │ ← 元信息
│ ───────────────────────── │ ← 分割线
│ 从前,在遥远的彩虹谷... │ ← 故事正文
├─────────────────────────────────┤
│ ┌─────────────────────────┐ │
│ │ ▶ 朗读故事 │ │ ← 底部朗读按钮
│ └─────────────────────────┘ │
└─────────────────────────────────┘
4.4 交互设计
4.4.1 操作方式
| 操作 | 手势 | 效果 |
|---|---|---|
| 添加关键词 | 点击推荐标签 | 追加到输入框 |
| 清除关键词 | 点击清除按钮 | 清空输入框 |
| 生成故事 | 点击生成按钮 | 启动生成流程 |
| 查看故事 | 点击故事卡片 | 打开详情面板 |
| 收藏故事 | 点击收藏按钮 | 切换收藏状态 |
| 朗读故事 | 点击朗读按钮 | 开始/暂停朗读 |
五、核心功能实现
5.1 故事生成
Future<void> _generateStory() async {
if (_keywordController.text.isEmpty) {
_showSnackBar('请输入关键词');
return;
}
setState(() {
_isGenerating = true;
_generationProgress = 0;
_currentStory = null;
});
for (int i = 0; i <= 10; i++) {
await Future.delayed(const Duration(milliseconds: 200));
if (!mounted) return;
setState(() {
_generationProgress = i / 10;
});
}
final story = StoryGenerator.generate(
keywords: _keywordController.text.split('、'),
);
if (!mounted) return;
setState(() {
_isGenerating = false;
_currentStory = story;
});
StoryStorage.addToHistory(story);
}
5.2 关键词添加
void _addKeyword(String keyword) {
final currentText = _keywordController.text;
if (currentText.isEmpty) {
_keywordController.text = keyword;
} else {
_keywordController.text = '$currentText、$keyword';
}
}
5.3 收藏切换
void _toggleFavorite() {
setState(() {
_isFavorite = !_isFavorite;
});
StoryStorage.toggleFavorite(widget.story.id);
}
5.4 星空背景构建
SliverToBoxAdapter(
child: Container(
height: 280,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
const Color(0xFF1a1a2e),
const Color(0xFF16213e),
colorScheme.surface,
],
),
),
child: Stack(
children: [
Positioned.fill(
child: CustomPaint(
painter: StarPainter(widget.starController),
),
),
// 月亮和标题
],
),
),
)
六、睡前故事知识拓展
6.1 睡前故事的作用
6.2 故事创作技巧
| 技巧 | 说明 |
|---|---|
| 简单情节 | 避免复杂的故事线 |
| 温馨氛围 | 营造安心舒适感 |
| 正面结局 | 给予美好期待 |
| 重复元素 | 增强记忆和安全感 |
| 柔和语言 | 使用温和的词汇 |
6.3 不同年龄段故事特点
| 年龄段 | 故事特点 | 推荐主题 |
|---|---|---|
| 0-2岁 | 简单重复、韵律感 | 动物、日常 |
| 3-5岁 | 想象丰富、情节简单 | 童话、冒险 |
| 6-8岁 | 情节完整、有教育意义 | 友谊、成长 |
| 9-12岁 | 内容丰富、有深度 | 科幻、历史 |
6.4 睡前故事发展趋势
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 朗读功能
| 功能 | 说明 |
|---|---|
| TTS集成 | 集成flutter_tts实现真实朗读 |
| 语速调节 | 可调节朗读速度 |
| 音量控制 | 可调节音量大小 |
| 语音选择 | 多种语音类型可选 |
7.2.2 存储功能
| 功能 | 说明 |
|---|---|
| 本地持久化 | 使用SQLite存储故事 |
| 云端同步 | 支持多设备同步 |
| 数据备份 | 支持数据导出备份 |
7.2.3 社交功能
| 功能 | 说明 |
|---|---|
| 故事分享 | 分享故事到社交平台 |
| 社区互动 | 用户故事交流社区 |
| 模板市场 | 用户创作模板分享 |
八、注意事项
8.1 开发注意事项
-
颜色处理:使用
withValues(alpha:)替代已废弃的withOpacity() -
动画释放:在dispose中释放AnimationController
-
状态同步:弹窗使用StatefulBuilder保持状态同步
-
历史上限:历史记录限制50条,防止内存溢出
-
关键词分隔:使用顿号(、)分隔多个关键词
8.2 用户体验优化
🌙 用户体验建议 🌙
- 星空背景营造沉浸感
- 生成进度可视化
- 故事卡片信息完整
- 详情面板可拖拽调整
8.3 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 星星不闪烁 | AnimationController未启动 | 检查repeat()调用 |
| 故事不显示 | _currentStory为null | 检查生成逻辑 |
| 收藏状态不同步 | 未调用setState | 使用StatefulBuilder |
| 历史记录丢失 | 内存存储重启清空 | 迁移至持久化存储 |
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
9.2 运行命令
# 查看可用设备
flutter devices
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_bedtime_story.dart
# 运行到Windows
flutter run -d windows -t lib/main_bedtime_story.dart
# 代码分析
flutter analyze lib/main_bedtime_story.dart
十、总结
晚安故事生成器应用通过"模板+词库替换"的策略,为用户提供个性化的睡前故事创作体验。应用内置3套故事模板,包含10种占位符类型,每种占位符有5个可选词汇,理论组合数约2900万种独特故事。
应用采用深色主题配合紫色主色调,营造梦幻氛围。创作页面顶部采用沉浸式星空设计,包含动态月亮和闪烁星星,为用户带来温馨的视觉体验。故事生成过程可视化,用户可以实时看到生成进度。
收藏管理功能支持用户收藏喜爱的故事,历史记录功能保留最近50条生成记录。故事详情采用可拖拽的底部面板设计,支持朗读功能(模拟实现,预留TTS接口)。设置页面提供朗读参数和生成偏好的配置入口。
应用采用Material Design设计规范,遵循Flutter最佳实践,代码结构清晰,易于维护和扩展。后续版本计划集成真实TTS、本地持久化存储、云端AI生成等功能,为用户提供更完善的故事创作体验。
晚安故事,陪伴甜美梦境!
更多推荐
所有评论(0)