feat(mobile-app): 开屏页改为随机静态图片模式

- 禁用帧动画,改为显示随机静态图片(3张中随机选1张)
- 显示3秒后自动跳转,保留跳过按钮
- 帧动画代码保留备用,可通过 _useStaticImage 开关切换
- 新增 splash_static 目录存放静态图片

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-09 08:19:25 -08:00
parent fabfbb73fe
commit 414fe95d04
5 changed files with 82 additions and 15 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

@ -1,3 +1,4 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -10,7 +11,7 @@ import '../../../../routes/app_router.dart';
import '../providers/auth_provider.dart'; import '../providers/auth_provider.dart';
/// - /// -
/// /// 3
class SplashPage extends ConsumerStatefulWidget { class SplashPage extends ConsumerStatefulWidget {
const SplashPage({super.key}); const SplashPage({super.key});
@ -19,6 +20,22 @@ class SplashPage extends ConsumerStatefulWidget {
} }
class _SplashPageState extends ConsumerState<SplashPage> { class _SplashPageState extends ConsumerState<SplashPage> {
// ========== ==========
/// 使false = 使
static const bool _useStaticImage = true;
///
static const int _staticDisplaySeconds = 3;
///
static const int _staticImageCount = 3;
/// (1-based)
late int _staticImageIndex;
// ========== ==========
/// ///
static const int _totalFrames = 36; static const int _totalFrames = 36;
@ -28,25 +45,55 @@ class _SplashPageState extends ConsumerState<SplashPage> {
/// (0-based) /// (0-based)
int _currentFrameIndex = 0; int _currentFrameIndex = 0;
///
final List<ImageProvider> _frameProviders = [];
// ========== ==========
/// ///
bool _showSkipButton = false; bool _showSkipButton = false;
/// ///
bool _isNavigating = false; bool _isNavigating = false;
/// /// /
bool _isPlaying = true; bool _isPlaying = true;
///
final List<ImageProvider> _frameProviders = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initializeFrames();
if (_useStaticImage) {
_initializeStaticImage();
} else {
_initializeFrames();
}
} }
/// ///
void _initializeStaticImage() {
// (1 _staticImageCount)
_staticImageIndex = Random().nextInt(_staticImageCount) + 1;
debugPrint('[SplashPage] 静态图片模式:显示 splash_$_staticImageIndex.jpg');
// 3
Future.delayed(Duration(seconds: _staticDisplaySeconds), () {
if (mounted && _isPlaying) {
_navigateToNextPage();
}
});
// 1
Future.delayed(const Duration(seconds: 1), () {
if (mounted) {
setState(() {
_showSkipButton = true;
});
}
});
}
///
void _initializeFrames() { void _initializeFrames() {
// ImageProvider // ImageProvider
for (int i = 1; i <= _totalFrames; i++) { for (int i = 1; i <= _totalFrames; i++) {
@ -71,11 +118,20 @@ class _SplashPageState extends ConsumerState<SplashPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
//
_precacheInitialFrames(); if (_useStaticImage) {
//
precacheImage(
AssetImage('assets/images/splash_static/splash_$_staticImageIndex.jpg'),
context,
);
} else {
//
_precacheInitialFrames();
}
} }
/// ///
void _precacheInitialFrames() { void _precacheInitialFrames() {
// 5 // 5
final framesToPrecache = _totalFrames < 5 ? _totalFrames : 5; final framesToPrecache = _totalFrames < 5 ? _totalFrames : 5;
@ -84,7 +140,7 @@ class _SplashPageState extends ConsumerState<SplashPage> {
} }
} }
/// ///
Future<void> _playAnimation() async { Future<void> _playAnimation() async {
final frameDuration = Duration(milliseconds: 1000 ~/ _frameRate); final frameDuration = Duration(milliseconds: 1000 ~/ _frameRate);
@ -110,7 +166,7 @@ class _SplashPageState extends ConsumerState<SplashPage> {
} }
} }
/// /// /
void _skipAnimation() { void _skipAnimation() {
_isPlaying = false; _isPlaying = false;
_navigateToNextPage(); _navigateToNextPage();
@ -222,8 +278,8 @@ class _SplashPageState extends ConsumerState<SplashPage> {
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
// // /
_buildFrameAnimation(), _useStaticImage ? _buildStaticImage() : _buildFrameAnimation(),
// //
if (_showSkipButton) if (_showSkipButton)
@ -237,7 +293,17 @@ class _SplashPageState extends ConsumerState<SplashPage> {
); );
} }
/// ///
Widget _buildStaticImage() {
return SizedBox.expand(
child: Image.asset(
'assets/images/splash_static/splash_$_staticImageIndex.jpg',
fit: BoxFit.cover,
),
);
}
///
Widget _buildFrameAnimation() { Widget _buildFrameAnimation() {
return SizedBox.expand( return SizedBox.expand(
child: Image( child: Image(

View File

@ -109,6 +109,7 @@ flutter:
- assets/images/avatars/ - assets/images/avatars/
- assets/images/illustrations/ - assets/images/illustrations/
- assets/images/splash_frames/ - assets/images/splash_frames/
- assets/images/splash_static/
- assets/icons/ - assets/icons/
- assets/icons/nav/ - assets/icons/nav/
- assets/icons/tokens/ - assets/icons/tokens/