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

栏目: IOS · 发布时间: 7年前

内容简介:本来是要做一个仿网易云音乐的flutter项目,但是因为最近事情比较多,项目周期跨度会比较长,因此分几个步骤来完成。这是仿网易云音乐项目系列文章的第一篇。没有完全照搬网易云音乐的UI,借鉴了其中的黑胶唱机动画。先贴上项目地址这个界面实现起来其实是比较简单的,大致分为如下几个部分:

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

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

初步效果图

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

思路

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

  • 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仿网易云音乐:播放界面》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

你不知道的JavaScript(上卷)

你不知道的JavaScript(上卷)

[美] Kyle Simpson / 赵望野、梁杰 / 人民邮电出版社 / 2015-4 / 49.00元

JavaScript语言有很多复杂的概念,但却用简单的方式体现出来(比如回调函数),因此,JavaScript开发者无需理解语言内部的原理,就能编写出功能全面的程序;就像收音机一样,你无需理解里面的管子和线圈都是做什么用的,只要会操作收音机上的按键,就可以收听你喜欢的节目。然而,JavaScript的这些复杂精妙的概念才是语言的精髓,即使是经验丰富的JavaScript开发者,如果没有认真学习也无......一起来看看 《你不知道的JavaScript(上卷)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换