写在前头

本来是要做一个仿网易云音乐的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

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

  1. 2.Android高仿网易云音乐-引导界面和广告界面实现

    效果图 效果图依次为图片广告,视频广告,引导界面. 系列文章目录导航 目录 1.实现分析 广告界面就是显示图片和视频,所以可以放一个图片控件,视频控件,然后跳过按钮,提示按钮,WiFi预加载提示都是放 ...

  2. Android高仿网易云音乐-启动界面实现和动态权限处理

    效果 实现分析 基本上没有什么难点,就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等. 布局 <?xml version="1.0" ...

  3. 《云阅》一个仿网易云音乐UI,使用Gank.Io及豆瓣Api开发的开源项目

    CloudReader 一款基于网易云音乐UI,使用GankIo及豆瓣api开发的符合Google Material Desgin阅读类的开源项目.项目采取的是Retrofit + RxJava + ...

  4. C# WPF 低仿网易云音乐(PC)歌词控件

    原文:C# WPF 低仿网易云音乐(PC)歌词控件 提醒:本篇博客记录了修改的过程,废话比较多,需要项目源码和看演示效果的直接拉到文章最底部~ 网易云音乐获取歌词的api地址 http://music ...

  5. C# WPF 低仿网易云音乐(PC)Banner动画控件

    原文:C# WPF 低仿网易云音乐(PC)Banner动画控件 由于技术有限没能做到一模一样的动画,只是粗略地做了一下.动画有点生硬,还有就是没做出网易云音乐的立体感.代码非常简单粗暴,而且我也写有很 ...

  6. iOS 开发仿网易云音乐歌词海报

    使用网易云音乐也是一个巧合,我之前一直使用QQ音乐听歌,前几天下 app 手机内存告急.于是就把QQ音乐给卸载掉了,正好晚上朋友圈里有一个朋友用网易云音乐分享了一首歌曲,于是我也就尝试下载了网易云音乐 ...

  7. 新鲜出炉高仿网易云音乐 APP

    我的引语 晚上好,我是吴小龙同学,我的公众号「一分钟GitHub」会推荐 GitHub 上好玩的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注我. 项目中成长是最快的,如何成长,就 ...

  8. android仿网易云音乐引导页、仿书旗小说Flutter版、ViewPager切换、爆炸菜单、风扇叶片效果等源码

    Android精选源码 复现网易云音乐引导页效果 高仿书旗小说 Flutter版,支持iOS.Android Android Srt和Ass字幕解析器 Material Design ViewPage ...

  9. WPF仿网易云音乐系列(序)

    1.简介 由于之前做了一个播放器,苦于不懂界面设计,只得去借鉴借鉴一些成功的作品,网易云音乐就甚合朕心,哈哈,最后做出来的效果如下: 本系列文章就来和大家讨论以下,如何用WPF去仿制一个网易云音乐来: ...

随机推荐

  1. 普通企业的规划类项目中,OptaPlanner更适合作为APS的规划优化引擎

    在企业的规划.优化场景中,均需要开发规划类的项目,实现从从种可能方案中找出相对最优方案.如排班.生产计划(包括高层次的供应链优化,到细粒度的车间甚至机台作业指令).车辆调度等.因为这类场景需要解决的问 ...

  2. .NET Core项目部署到Linux(Centos7)(六)发布.NET Core 项目到Linux

    目录 1.前言 2.环境和软件的准备 3.创建.NET Core API项目 4.VMware Workstation虚拟机及Centos 7安装 5.Centos 7安装.NET Core环境 6. ...

  3. Java时间戳获取

    Java时间戳获取方式: 1:New Date().getTime(); 2: System.currentTimeMillis();区别: New Date().getTime()的底层其实是Sys ...

  4. 在线优化算法 FTRL 的原理与实现

    在线学习想要解决的问题 在线学习 ( \(\it{Online \;Learning}\) ) 代表了一系列机器学习算法,特点是每来一个样本就能训练,能够根据线上反馈数据,实时快速地进行模型调整,使得 ...

  5. SpringBoot系列(五)Mybatis整合完整详细版

    SpringBoot系列(五)Mybatis整合 目录 mybatis简介 项目创建 entity dao service serviceImpl mapper controller 1. Mybat ...

  6. 如何增加Tomcat内存

    有时候在开发中,常常遇到内存溢出问题,很有可能项目过大,导致Tomcat内存不足问题,那么此时就要给Tomcat添加内存了,如,操作如下 1. 先找到Tomcat目录下的catalina.bat文件

  7. c++容器的底层数据结构

    序列式容器 vector ->底层数据结构为数组,支持快速随机访问 list ->底层数据结构为双向链表,支持快速增加和删除 deque ->底层数据结构为一个中央控制器和多个缓冲区 ...

  8. synchronized 与 volatile 区别 还有 volatile 的含义

    熟悉并发的同学一定知道在java中处理并发主要有两种方式: 1,synchronized关键字,这个大家应当都各种面试和笔试中经常遇到. 2,volatile修饰符的使用,相信这个修饰符大家平时在项目 ...

  9. AJ学IOS(49)多线程网络之线程的创建NSThreand

    AJ分享,必须精品 一:NSThread的基本使用 1:创建和启动线程 一个NSThread对象就代表一条线程 创建.启动线程 NSThread *thread = [[NSThread alloc] ...

  10. ClickOnce的安装路径

    win 7下C:\Users\Administrator.U5G4L4PUY34SH5C\AppData\Local\Apps\2.0\KPVZOAYK.0JE\56B55RCH.A7A\winr.. ...