Flutter仿网易云音乐:播放界面

2023-11-04

写在前头

本来是要做一个仿网易云音乐的flutter项目,但是因为最近事情比较多,项目周期跨度会比较长,因此分几个步骤来完成。这是仿网易云音乐项目系列文章的第一篇。没有完全照搬网易云音乐的UI,借鉴了其中的黑胶唱机动画。

先贴上项目地址 github.com/KinsomyJS/f…

初步效果图

思路

这个界面实现起来其实是比较简单的,大致分为如下几个部分:

  • 1.背景的高斯模糊效果
  • 2.黑胶唱头的旋转动画
  • 3.黑胶唱片的旋转动画
  • 4.下部控制器和进度条部分

我们一个个来说实现过程。

实践

整个界面是一个堆叠视图,最下面是一个背景图片,上面覆盖一层高斯模糊半透明遮罩,再上层是title,黑胶唱机和控制器。

1. 背景高斯模糊

首先使用stack组件用来包裹堆叠视图,在里面有两个container,第一个是背景网络图片,第二个就是一个BackdropFilter

Stack(
      children: <Widget>[
        new Container(
          decoration: new BoxDecoration(
            image: new DecorationImage(
              image: new NetworkImage(coverArt),
              fit: BoxFit.cover,
              colorFilter: new ColorFilter.mode(
                Colors.black54,
                BlendMode.overlay,
              ),
            ),
          ),
        ),
        new Container(
            child: new BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
          child: Opacity(
            opacity: 0.6,
            child: new Container(
              decoration: new BoxDecoration(
                color: Colors.grey.shade900,
              ),
            ),
          ),
        )),
        
        ...
    ]
复制代码

这里的高斯模糊sigmaX和sigmaY的值选择了10,然后透明度为0.6,颜色为grey.shade900。

2.黑胶唱头的旋转动画

关于动画的知识这里就不做详细介绍了,可以参考官方文档传送门

自定义动画组件在needle_anim.dart文件里。 这里将动画和组件解耦,分别定义了动画过程类PivotTransition,顾名思义围绕一个支点旋转,继承自AnimatedWidget

支点定在child组件的topcenter位置。 注意turns不能为空,需要根据turns的值计算旋转绕过的周长,围绕Z轴旋转。

class PivotTransition extends AnimatedWidget {
  /// 创建旋转变换
  /// turns不能为空.
  PivotTransition({
    Key key,
    this.alignment: FractionalOffset.topCenter,
    @required Animation<double> turns,
    this.child,
  }) : super(key: key, listenable: turns);

  /// The animation that controls the rotation of the child.
  /// If the current value of the turns animation is v, the child will be
  /// rotated v * 2 * pi radians before being painted.
  Animation<double> get turns => listenable;

  /// The pivot point to rotate around.
  final FractionalOffset alignment;

  /// The widget below this widget in the tree.
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final double turnsValue = turns.value;
    final Matrix4 transform = new Matrix4.rotationZ(turnsValue * pi * 2.0);
    return new Transform(
      transform: transform,
      alignment: alignment,
      child: child,
    );
  }
}
复制代码

接下来就是自定义黑胶唱头组件。

final _rotateTween = new Tween<double>(begin: -0.15, end: 0.0);
new Container(
  child: new PivotTransition(
    turns: _rotateTween.animate(controller_needle),
    alignment: FractionalOffset.topLeft,
    child: new Container(
      width: 100.0,
      child: new Image.asset("images/play_needle.png"),
    ),
  ),
),

复制代码

将png图片包裹在container内作为child参数传递给PivotTransition

外部使用的时候传入一个Tween,起始位置为-0.15 ~ 0.0。

3.黑胶唱片的旋转动画

这部分代码在record_anim.dart文件内。使用了package:flutter/animation.dart提供的RotationTransition做旋转,很简单。

class RotateRecord extends AnimatedWidget {
  RotateRecord({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Container(
      margin: new EdgeInsets.symmetric(vertical: 10.0),
      height: 250.0,
      width: 250.0,
      child: new RotationTransition(
          turns: animation,
          child: new Container(
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              image: DecorationImage(
                image: NetworkImage(
                    "https://images-na.ssl-images-amazon.com/images/I/51inO4DBH0L._SS500.jpg"),
              ),
            ),
          )),
    );
  }
}
复制代码

接着自定义旋转动画的控制逻辑。旋转一圈用时十五秒钟,速度为线性匀速,同时会重复旋转动画。

controller_record = new AnimationController(
        duration: const Duration(milliseconds: 15000), vsync: this);
animation_record =
        new CurvedAnimation(parent: controller_record, curve: Curves.linear);
animation_record.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    controller_record.repeat();
  } else if (status == AnimationStatus.dismissed) {
    controller_record.forward();
  }
});
复制代码

4.下部控制器和进度条部分

播放流媒体音频使用了三方组件audioplayers,具体代码在player_page.dart文件内,封装了一个player组件,接受了一系列参数包括音频路径,播放操作回调等。该组件支持本地资源和网络资源,这里用网络音频资源做demo。

const Player(
      {@required this.audioUrl,
      @required this.onCompleted,
      @required this.onError,
      @required this.onNext,
      @required this.onPrevious,
      this.key,
      this.volume: 1.0,
      this.onPlaying,
      this.color: Colors.white,
      this.isLocal: false});
复制代码

在initState方法里初始化AudioPlayer对象。".."是dart的级联操作符。

 audioPlayer = new AudioPlayer();
    audioPlayer
      ..completionHandler = widget.onCompleted
      ..errorHandler = widget.onError
      ..durationHandler = ((duration) {
        setState(() {
          this.duration = duration;

          if (position != null) {
            this.sliderValue = (position.inSeconds / duration.inSeconds);
          }
        });
      })
      ..positionHandler = ((position) {
        setState(() {
          this.position = position;

          if (duration != null) {
            this.sliderValue = (position.inSeconds / duration.inSeconds);
          }
        });
      });
复制代码

开始播放代码

audioPlayer.play(
    widget.audioUrl,
    isLocal: widget.isLocal,
    volume: widget.volume,
  );
复制代码

开始播放后,durationHandler会回调音频总时长,positionHandler会回调播放进度,两个回调都返回一个Duration对象。根据这两个duration对象可以计算机播放进度的百分比,这里使用Slider组件做进度条。

new Slider(
    onChanged: (newValue) {
      if (duration != null) {
        int seconds = (duration.inSeconds * newValue).round();
        print("audioPlayer.seek: $seconds");
        audioPlayer.seek(new Duration(seconds: seconds));
      }
    },
    value: sliderValue ?? 0.0,
    activeColor: widget.color,
  ),
复制代码

总结

整体实现是非常简单的,只要对flutter的组件有所了解就能很快写出来,后面还会加入歌词滚动功能来丰富界面。

具体项目可以到 github.com/KinsomyJS/f… 查看,也欢迎star持续关注。

参考资料

  1. 官方文档
  2. pub: audioplayers
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter仿网易云音乐:播放界面 的相关文章

  • iOS逆向工程之App脱壳

    本篇博客以微信为例 给微信脱壳 砸壳 在iOS逆向工程中是经常做的一件事情 因为从AppStore直接下载安装的App是加壳的 其实就是经过加密的 这个 砸壳 的过程就是一个解密的过程 未砸壳的App是无法在Class dump Hoppe
  • string (std::string)转换为QString的用法(含中文)

    string s 123 QString str QString fromStdString s 含中文时的转换 std string str 你好世界 QString Name QString fromLocal8Bit str c st
  • 虹软人脸识别 - ArcFace SDK介绍及使用注意事项

    很多朋友在开发人脸识别系统的时候 会遇到各种各样的问题 现在我们以安卓平台使用虹软的免费离线人脸识别SDK开发为例 给大家介绍一下如何开发一个带有图片的人脸检测 视频画面的人脸属性检测 人脸注册识别等功能的人脸识别系统 一 获取SDK 1
  • (ps2019)Photoshop 2019 最新破解版下载

    Photoshop CC 2019新增功能 下载地址点我 新功能介绍 https helpx adobe com cn photoshop using whats new html 经过改良设计的内容识别填充 借助 Adobe Sensei
  • Jquery ligerui下拉框复选,使下拉框中相应值对勾选中

    othertypeCombox ligerGetComboBoxManager selectValue 1 2 3 4 othertypeCombox ligerGetComboBoxManager bulidContent 必须加上后一行
  • HTTP协议简介,数据安全 如何保证http传输安全性,http与https区别

    目前大多数网站和app的接口都是采用http协议 但是http协议很容易就通过抓包工具监听到内容 甚至可以篡改内容 为了保证数据不被别人看到和修改 可以通过以下几个方面避免 重要的数据 要加密 比如用户名密码 我们需要加密 这样即使被抓包监
  • android Scroller

    参考 http www linuxidc com Linux 2016 01 127276 htm 以前只知道怎么使用scroller 照猫画虎 复制粘贴 今天遇到使用scroller 还是要去搜索 这样不行 要搞懂原理 上面的博客写的很漂
  • iOS 自定义弹出框

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 在iOS中 系统再带的弹出窗体不好扩展 开发时候不如自定义一个弹出窗体 附加上显示和消失的动画 弹出窗体父类如下 具体效果直接往上面添加控件就行 ViewControlle
  • Android Framework——进程间通讯学习,从Binder使用看起

    前言 Binder 是安卓中非常重要的进程间通讯工具 通过Binder 安卓在ServiceManager中对外提供了一系列的服务 学习Binder 将很好地为我们学习framework开个好头 Android 使用多进程 Android
  • Unity中UI框架的使用1-添加面板、显示Loading页面

    其中BasePanel和Canvas都是挂在面板的预制物上的 1 导入我们的UI框架 本篇文章中有用的是两个UIPanelType NUIManager和NBasePanel 会放在文章最后供大家使用 2 先将我们做好的Panel设置成预制
  • Linux宝塔面板命令大全,快速学会

    cd www server panel python tools py panel 123456 查看宝塔日志 cat tmp panelBoot pl 查看软件安装日志 cat tmp panelExec log 站点配置文件位置 www
  • Android4.0 SDK功能详解

    我在eoe的论坛找到的 就复制过来了 跟大家分享一下 Android 4 0 平台API等级 14 Android 4 0 是一次重要的平台发布版 为用户和应用程序开发者增加了大量的新特性 在下面我们将讨论的所有新特性和API中 因为它将
  • 【QView】基于QML的UI组件框架 之 AImage (图片)

    先上结果演示 环境 不说版本就是耍流氓 硬件 通用PC 手机 Jetson Xavier NX 套件 均测试有效 系统 Ubuntu 20 04 Android Windows 均测试有效 软件 基于QT6 2 4 Qml 功能描述 AIm
  • UI自动化测试方案

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读1 3k次 点赞60次 收藏8次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自动
  • UI 易用性测试 以及自动化实现!

    GUI 是指图形用户界面 UI 是指用户界面 对于纯软件系统 这两者没有本质的区别 GUI易用性测试与 UI 易用性测试内容一致 但是如果测试的对象是一个产品 这两者则存在区别 对于产品 UI 则不仅仅包括 GUI 还包括产品硬件部分的测试
  • Axure RP 8 for Mac/win中文版:打造完美交互式原型设计体验

    Axure RP 8 一款引领潮流的交互式原型设计工具 为设计师提供了无限的可能性 让他们能够创造出逼真的原型 从而更好地展示和测试他们的设计 Axure RP 8拥有丰富的功能和工具 让设计师可以轻松地创建出复杂的交互式原型 从简单的按钮
  • 独立搭建UI自动化测试框架分享

    今天给大家分享一个selenium testng maven ant的UI自动化 可以用于功能测试 也可按复杂的业务流程编写测试用例 今天此篇文章不过多讲解如何实现CI CD 只讲解自己能独立搭建UI框架 如果有其他好的框架也可以联系我 分
  • element ui弹窗在别的弹窗下方,优先级不高的问题

    在 弹窗 的标签中加入append to body即可解决该问题
  • element ui弹窗在别的弹窗下方,优先级不高的问题

    在 弹窗 的标签中加入append to body即可解决该问题
  • OpenHarmony沙箱文件

    一 前言 1 前景提要 DevEcoStudio版本 DevEco Studio 3 1 Release SDK版本 3 2 2 5 API版本 9 2 概念 在openharmony文件管理模块中 按文件所有者分类分为应用文件和用户文件和

随机推荐

  • vim后,/要搜索字段,n(查找)

    vim后 要搜索字段 回车 n 查找
  • 测试测试测试

    目录 标题 标题 测试
  • Mysql索引

    1 什么是索引 索引是帮助MySQL高效获取数据的数据结构 2 索引的分类 单列索引 1 普通索引 mysql中的普通索引 允许插入重复值和null值 没有什么限制 纯粹为了查询快一点 2 唯一索引 索引中的列必须是唯一的 可以为null值
  • oracle 不带时分秒,关于Oracle数据库不带日期中时分秒的查询

    关于Oralce数据库 的日期时间查询 下面我们先来看一组日期数据 表 myDate 列 time 1998 8 7 23 45 33 3 1998 8 7 11 22 21 5 1998 8 7 00 00 00 0 上面列出的这组日期数
  • 50-00-010-配置-kylin-2.6.0官网配置

    文章目录 1 视界 1 Kylin 配置 2 配置文件及参数重写 3 Kylin 配置文件 配置重写 项目级别配置重写 Cube 级别配置重写 MapReduce 任务配置重写 Hive 任务配置重写 Spark 任务配置重写 部署配置 部
  • linux下部分文件管理类基本命令汇总以及bash展开特性介绍

    一 文件管理类基本命令 1 1 表格汇总 今天要讲解的命令如下表所示 按照外部命令和内建命令做基本划分 内建命令列表 命令名字 基本说明 file 检测文件类型 cd 改变shell的工作目录 dirs 显示目录堆栈信息 popd 从堆栈中
  • macOS_Monterey_12.6_21G115可引导可虚拟机安装的纯净版苹果OS系统ISO镜像安装包免费下载

    现在网络上黑果系统出现了许多多合一的多功能版 不是说这些版本不好 只是小编个人觉得 操作系统就是用来使用的 黑果本来就是服务于一些非苹果机的苹果OS爱好者的 简洁稳定应该是首选 固小编毅然放弃那些多功能的豪华版镜像版 独宠我的纯净可引导安装
  • pyqt5重温入门教程:用Qt Designer设计UI

    程序员今晚不回家 抖音号 在开始教程之前 先简单地水几句 之前使用过pyqt5 但是好久没用了 现在因为有一个项目需要 所以在此重温一下 当然教程就不是像零基础那样手把手从安装开始了 这里简洁明了 直接上手操作 第一步 打开Designer
  • 某宝sign参数逆向分析

    说明 淘宝ajax获取数据的方式为jsonp请求 所以在chrome中使用xhr拦截请求中加密参数的方式拦截不到 解决办法 目前我使用的方法是 添加DOM断点的方法去监听页面元素的变化 同时使用charles去监听页面发送的请求 后面就是一
  • 简单粗暴而又很有效果的图片无损放大方法

    工作生活中我们都会碰到想要对图片进行无损放大的情况 比如说做电子相册视频啦 做PPT啦 做设计啦等等等等 但是我们又没有那么专业的技术 PS也能试着操作一下 但始终没法弄能自己想要的效果 我们该如何对图片进行快速的无损放大呢 用PhotoZ
  • uart_linux

    写串口程序 include
  • vue.js中props,watch深度监听对象时,对象新增或者删除属性值时深度监听失效

    使用 deep 选项时 仅会监听对象内部现有属性值的改变 不会监听对象属性的增加或删除操作 原因是 deep 选项仅能监听对象内部属性的改变 当对象新增或删除属性时 这些操作并不会触发属性内部变化引起的更新 解决方案1 this obj O
  • DTFD-MIL: Double-Tier Feature Distillation Multiple Instance Learning for WSI_论文笔记

    文章链接 https arxiv org pdf 2203 12081 pdf 一 摘要 多实例学习 MIL 在组织病理学全切片图像分类中的应用越来越广泛 然而 用于这一特定分类问题的MIL方法仍然面临着独特的挑战 特别是那些与小样本队列相
  • antd4 tree带搜索框的可编辑树实现(hooks+ts)

    需求背景 实现带搜索框的可编辑树 有以下功能在 1 搜索相关节点高亮 2 配合treeSelect规范数据处理 3 节点可添加和编辑 编辑可修改上级 4 节点可删除 5 移入显示编辑图标 0 带搜索框的树 默认数据 搜索exa后 搜索exa
  • c#中的queue和stack

    using System using System Collections 队列Queue的using引用 using System Collections Generic using System Linq using System Te
  • JAVA基础

    目录 1 数据类型 2 注释模式 3 进制 4 浮点数拓展 5 字符拓展 6 运算中不同类型的数据先转化同一类型然后进行运算 7 变量 8 运算符 9 包机制 1 数据类型 强类型语言 变量必须定义才能使用 public class Dem
  • 这几款软件,你千万别装

    目录 写在前面 一 鲁大师 旧版 二 360全家桶 三 2345全家桶 四 快压 结束语 写在前面 很多人都会在自己的电脑上装上Ghost Windows 其实这样并不好 虽然不用激活 但是也有很多的捆绑软件 今天我就为大家盘点一下哪些软件
  • Android8打印功能,[翻译]Android 8.1 默认打印服务的中间人攻击漏洞披露

    漏洞概述 Android 8 1引入了默认打印服务 默认打印服务 基于Mopria联盟在谷歌应用商店发布的免费应用 Mopria Print Service 因其缺乏验证 所以会导致中间人攻击并被拦截后续的打印作业 还会造成在使用潜在不安全
  • 简单易懂SpringBoot和Android上传和下载文件方案——采用URL

    上传思路 SpringBoot把文件保存在静态资源里 并且开启静态资源访问 数据库保存文件的URL地址 URL地址是一个字符串 Android采用OkHttp上传文件 下载思路 SpringBoot从数据库获取URL地址发送给Android
  • Flutter仿网易云音乐:播放界面

    写在前头 本来是要做一个仿网易云音乐的flutter项目 但是因为最近事情比较多 项目周期跨度会比较长 因此分几个步骤来完成 这是仿网易云音乐项目系列文章的第一篇 没有完全照搬网易云音乐的UI 借鉴了其中的黑胶唱机动画 先贴上项目地址 gi