5.9 KiB
5.9 KiB
关于页面「小狗乐园」彩蛋设计
背景
在「关于鸭鸭日历」页面中,版本号目前是一个无实际功能的 TextButton。本设计为其增加一个隐藏彩蛋:连续点击版本号 7 次后进入「小狗乐园」页面,全屏循环播放一段彩蛋视频。
目标
- 提升应用趣味性,给用户一个可发现的隐藏彩蛋。
- 保持现有架构:所有 UI 与业务逻辑留在
:core,:app仅作为 Activity 壳。 - 不引入过度复杂的依赖或状态管理。
设计决策摘要
| 决策项 | 选择 | 说明 |
|---|---|---|
| 总点击次数 | 7 次 | 足够隐藏,又不会太难触发 |
| 提示开始时机 | 第 4 次点击 | 前 3 次静默,避免普通用户误触时被打扰 |
| 提示文案 | 「再点击 N 下进入小狗乐园」 | N 为剩余次数,简洁明确 |
| 超时重置 | 1.5 秒 | 与 Android 开发者选项等经典彩蛋保持一致节奏 |
| 进度持久化 | 不持久化 | 离开页面或超时即重置 |
| 提示组件 | 系统 Toast | 最符合「小气泡」语义,轻量 |
| 视频播放 | Media3 ExoPlayer | 功能强、与 Compose 集成成熟 |
| 视频位置 | core/src/main/assets/video/enter_screen_bg1.mp4 |
与现有 app_icon.webp 等资源保持一致 |
| 视频显示 | 等比裁剪铺满(RESIZE_MODE_ZOOM) |
填满屏幕,视觉沉浸 |
| 声音 | 静音 | 不打扰用户 |
| 屏幕方向 | 跟随系统 | 不强制横竖屏 |
| 退出方式 | 系统返回键 | 支持预测性返回手势,Activity 自然 finish |
| 进入过渡动画 | 淡入 400ms | 营造进入彩蛋的仪式感 |
| 退出过渡动画 | 默认 slide | 保持现有返回风格 |
触发机制(关于页面)
状态
- 在
AboutScreen内使用remember { mutableIntStateOf(0) }保存当前连续点击次数。 - 计数为局部状态,不提升到 ViewModel,也不持久化。
AboutScreen离开 Composition 时计数自然消失。
点击行为
| 当前点击次数 | 行为 |
|---|---|
| 1 ~ 3 | 计数 +1,无 Toast |
| 4 | Toast「再点击 3 下进入小狗乐园」 |
| 5 | Toast「再点击 2 下进入小狗乐园」 |
| 6 | Toast「再点击 1 下进入小狗乐园」 |
| 7 | 调用 onNavigateToDogPark(),进入彩蛋页面 |
超时重置
每次点击启动/重启一个 LaunchedEffect:
- 在 1.5 秒内收到下一次点击:取消旧 Job,计数 +1。
- 1.5 秒内无新点击:Job 执行,计数重置为 0。
导航链路
MainActivity
└── startActivityWithSlide → AboutActivity
└── onNavigateToDogPark → startActivityWithSlide → DogParkActivity
AboutActivity给AboutScreen新增回调onNavigateToDogPark: () -> Unit。DogParkActivity继承BaseActivity,自动获得 edge-to-edge 和 slide 转场支持。
小狗乐园页面
组件
DogParkScreen:位于:core,无业务参数,只负责全屏视频播放。DogParkActivity:位于:app,继承BaseActivity,壳逻辑。
视频播放
- 使用 Media3 ExoPlayer +
PlayerView。 - 通过 Compose
AndroidView嵌入PlayerView。 - 配置:
resizeMode = RESIZE_MODE_ZOOM:等比裁剪铺满全屏。useController = false:不显示播放控件。player.volume = 0f:静音。repeatMode = Player.REPEAT_MODE_ONE:循环播放。
- 媒体源 URI:
asset:///video/enter_screen_bg1.mp4。
生命周期
onStart→player.play()onStop→player.pause()onDestroy→player.release()- 使用
DisposableEffect绑定释放逻辑。
退出
- 用户按系统返回键或执行返回手势时 Activity finish。
- 预测性返回手势由 Manifest 中的
android:enableOnBackInvokedCallback="true"支持。 - 退出动画保留
BaseActivity默认 slide。
过渡动画
进入动画(淡入)
- 新增
app/src/main/res/anim/fade_in.xml。 DogParkActivity.onCreate中:- Android 14+:
overrideActivityTransition(OVERRIDE_TRANSITION_OPEN, R.anim.fade_in, R.anim.fade_out) - 低版本:
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)(在super.onCreate之后、setContent之前调用)
- Android 14+:
- 淡入时长约 400ms。
退出动画
- 保留
BaseActivity默认的 slide 返回动画,不覆盖。
资源
- 视频文件:
- 来源:
~/Pictures/enter_screen_bg1.mp4 - 目标:
core/src/main/assets/video/enter_screen_bg1.mp4
- 来源:
- 动画资源:
- 新增
app/src/main/res/anim/fade_in.xml
- 新增
依赖变更
gradle/libs.versions.toml
新增:
[versions]
androidx-media3 = "1.6.1"
[libraries]
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "androidx-media3" }
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "androidx-media3" }
core/build.gradle.kts
新增:
implementation(libs.androidx.media3.exoplayer)
implementation(libs.androidx.media3.ui)
错误处理
- 视频加载/准备失败时,直接
finishWithSlideBack()静默返回关于页面。 - 不显示弹窗或 Snackbar,避免破坏彩蛋体验。
测试计划
单元测试
- 抽离纯函数
getToastMessage(clickCount: Int): String?并测试:- 1 ~ 3 返回
null - 4 返回「再点击 3 下进入小狗乐园」
- 5 返回「再点击 2 下进入小狗乐园」
- 6 返回「再点击 1 下进入小狗乐园」
- 7 返回
null(此时已跳转)
- 1 ~ 3 返回
手动测试
- 连续点击版本号 7 次,确认进入
DogParkActivity。 - 点击过程中停顿 1.5 秒,确认计数重置。
- 确认进入动画为淡入。
- 确认视频全屏、静音、无控件、循环播放。
- 确认系统返回键正常退出,并回到关于页面。
- 确认低版本(< Android 14)和 Android 14+ 的淡入动画都生效。
未包含在本期
- 多次进入彩蛋后的不同内容。
- 视频下载/动态更新。
- 屏幕常亮保持。
- 分享彩蛋入口。