【无标题】

Flutter for OpenHarmony 音乐播放器App实战01 - 启动闪屏实现

作为音乐播放器系列的开篇,我们先来实现一个带有动画效果的启动闪屏页面。闪屏页面是用户打开App后看到的第一个界面,一个好的闪屏设计能给用户留下深刻的第一印象。

功能分析

我们要实现的闪屏页面包含以下功能:

  • 渐变背景,从粉色过渡到紫色,营造音乐氛围
  • Logo图标带有弹性缩放动画,从小变大
  • 3秒倒计时自动跳转到主页
  • 右上角"跳过"按钮,用户可以手动跳过
  • 底部显示版本号信息

核心技术点

这个页面主要用到了Flutter的动画系统。我们使用AnimationController配合Tween来实现Logo的弹性缩放效果,同时用Future.delayed实现倒计时逻辑。

完整代码实现

dart 复制代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'main_page.dart';

class SplashPage extends StatefulWidget {
  const SplashPage({super.key});

  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> with TickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _scaleAnim;
  int _countdown = 3;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
    _scaleAnim = Tween<double>(begin: 0.5, end: 1.0).animate(CurvedAnimation(parent: _controller, curve: Curves.elasticOut));
    _controller.forward();
    _startCountdown();
  }

  void _startCountdown() {
    Future.delayed(const Duration(seconds: 1), () {
      if (mounted && _countdown > 0) {
        setState(() => _countdown--);
        _startCountdown();
      } else if (mounted) {
        Get.off(() => const MainPage());
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFE91E63), Color(0xFF9C27B0)])),
        child: SafeArea(
          child: Stack(
            children: [
              Center(
                child: ScaleTransition(
                  scale: _scaleAnim,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Container(
                        width: 120, height: 120,
                        decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(30), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.3), blurRadius: 20)]),
                        child: const Icon(Icons.music_note, size: 60, color: Color(0xFFE91E63)),
                      ),
                      const SizedBox(height: 24),
                      const Text('音乐播放器', style: TextStyle(color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold)),
                      const SizedBox(height: 8),
                      const Text('聆听世界的声音', style: TextStyle(color: Colors.white70, fontSize: 14)),
                    ],
                  ),
                ),
              ),
              Positioned(
                top: 16, right: 16,
                child: GestureDetector(
                  onTap: () => Get.off(() => const MainPage()),
                  child: Container(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    decoration: BoxDecoration(color: Colors.black26, borderRadius: BorderRadius.circular(20)),
                    child: Text('跳过 $_countdown', style: const TextStyle(color: Colors.white)),
                  ),
                ),
              ),
              const Positioned(bottom: 32, left: 0, right: 0, child: Center(child: Text('Version 1.0.0', style: TextStyle(color: Colors.white38)))),
            ],
          ),
        ),
      ),
    );
  }
}

代码详解

动画控制器初始化

在initState中,我们创建了一个持续1秒的动画控制器。TickerProviderStateMixin为动画提供了时钟信号,这是Flutter动画系统的基础。

dart 复制代码
_controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);

弹性缩放动画

使用Tween定义动画的起始值0.5和结束值1.0,配合Curves.elasticOut曲线实现弹性效果。这个曲线会让动画在结束时有一个回弹的感觉,非常适合Logo展示。

dart 复制代码
_scaleAnim = Tween<double>(begin: 0.5, end: 1.0).animate(CurvedAnimation(parent: _controller, curve: Curves.elasticOut));

倒计时逻辑

_startCountdown方法使用递归调用Future.delayed来实现倒计时。每隔1秒检查一次,如果倒计时未结束就继续,否则跳转到主页。这里用mounted判断组件是否还在树中,避免在页面销毁后调用setState导致报错。

dart 复制代码
void _startCountdown() {
  Future.delayed(const Duration(seconds: 1), () {
    if (mounted && _countdown > 0) {
      setState(() => _countdown--);
      _startCountdown();
    } else if (mounted) {
      Get.off(() => const MainPage());
    }
  });
}

渐变背景

使用LinearGradient创建从左上到右下的渐变效果,粉色到紫色的过渡很好地呼应了音乐App的主题色。

dart 复制代码
decoration: const BoxDecoration(gradient: LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [Color(0xFFE91E63), Color(0xFF9C27B0)]))

跳过按钮

右上角的跳过按钮使用Positioned定位在Stack中。点击后直接调用Get.off跳转到主页,off方法会替换当前路由,用户无法返回闪屏页。

页面跳转

我们使用GetX的路由管理,Get.off会替换当前页面而不是压入新页面,这样用户按返回键不会回到闪屏页,符合正常的App使用逻辑。

小结

这个闪屏页面虽然简单,但涵盖了Flutter开发中常用的几个知识点:动画系统、定时器、路由跳转、渐变装饰等。在实际项目中,你可以在这个基础上添加更多元素,比如加载进度、网络请求等。


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

相关推荐
IT_陈寒12 分钟前
JavaScript实战技巧总结:深挖数组遍历的性能陷阱与实战解法
前端·人工智能·后端
步行cgn20 分钟前
为什么既要 web.xml 又要 springmvc.xml?能不能只配一个?
xml·前端·hive
风骏时光牛马27 分钟前
大模型综合能力评测:多维度性能与对齐效果对比
前端
winfredzhang32 分钟前
从零手写一个毛玻璃风格的页面搭建台:单文件 HTML 实现组件放置、面板磁吸与图层管理
前端·html
OxYGC33 分钟前
[工程] PHP2Shell 漏洞解析:两条 PHP 内核 RCE,为什么应用层的防护全部失效
android·开发语言·php
小徐不徐说36 分钟前
数据库存储基础:理解表结构、主键、事务与 BLOB
开发语言·数据库·c++·qt·程序设计
草莓熊Lotso1 小时前
【C++ 基于微服务的即时通讯系统】网关基建:cpp-httplib 与 WebSocketpp 从入门到实战
linux·开发语言·数据库·c++·redis·微服务·云原生
李纲明1 小时前
WordPress 媒体库上传失败或一直转圈:先核 PHP 上传限制与目录权限,再查安全插件与对象存储
运维·开发语言·安全·php·wordpress·媒体库·devdiy
葡萄城技术团队9 小时前
1000 人协同压测的环境瓶颈排查:CPU 争用与 Wi\-Fi
前端
第九序言T9 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理