Android开发程序员痛心事迹:实现音乐播放界面,模仿网易云音乐

573 阅读3分钟

PS:今天偶然听到消息,我也是惊了!网易云音乐暂时下架了,内心就是五味陈杂。

由于最近自己在做一个音乐APP,在播放音乐时,想实现网易云那种带光盘和指针的界面,所以在查找了许多的学习教程,对网易云音乐的消息也特别的关注。

同时也希望有知情的大佬评论一下,网易云音乐到底怎么了?

以下是我的学习制作过程,先放出网易云播放界面

1.隐藏statusBar

//隐藏statusBar,第一个参数是新窗口的标志位,第二个参数时要修改的标志位
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

2.布局文件(暂时添加返回按钮、背景、歌名和作者)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".activities.PlayMusicActivity">
 <ImageView
 android:id="@+id/iv_bg"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="centerCrop"
 android:src="@mipmap/album1"
 />
 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:src="@mipmap/no_bar_back"
 android:layout_margin="@dimen/marginSize"
 android:onClick="onBackClick"/>
 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 android:gravity="center_horizontal"
 android:layout_marginTop="480dp">
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="音乐名称"
 android:textColor="@android:color/white"
 android:textSize="@dimen/textSize"
 android:textStyle="bold"/>
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="@dimen/marginSize"
 android:textSize="@dimen/infoSize"
 android:text="作者"
 android:textColor="@android:color/white"/>
 </LinearLayout>
</FrameLayout>

3.设置背景模糊

使用GlideTransTransformations包

(1) 引入包(app/build.gradle)

//如果没有引入Glide的包也要记得引入,因为两者是配合使用的
 implementation 'com.github.bumptech.glide:glide:4.9.0'
 //glide-transformation
 implementation 'jp.wasabeef:glide-transformations:4.0.1'

(2) 加载图片,这里设置效果为模糊,具体的其他效果可以参考github中该包的详细说明,地址是 github.com/wasabeef/gl…

(3) 操作代码,load中的可以是网络图片url,也可以是模块中的文件

iv_bg = this.findViewById(R.id.iv_bg);
 //glide-transformation
 Glide.with(this)
 .load(R.mipmap.album1)
 .apply(RequestOptions.bitmapTransform(new BlurTransformation(25,10)))
 .into(iv_bg);

(4) 效果

4.自定义带指针光盘的View

(1) 指针

(2) 光盘

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 xmlns:app="http://schemas.android.com/apk/res-auto">
 <!--光盘-->
 <FrameLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="@dimen/discTopSize">
 
 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:src="@mipmap/disc" />
 <!--CircleImageView-->
 <de.hdodenhof.circleimageview.CircleImageView
 android:id="@+id/cv_icon"
 android:layout_width="@dimen/playMusicIconSize"
 android:layout_height="@dimen/playMusicIconSize"
 android:layout_gravity="center"
 app:civ_border_width="2dp"
 app:civ_border_color="@android:color/black"/>
 <!--播放按钮-->
 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:src="@mipmap/play_music"
 android:layout_gravity="center"
 android:visibility="gone"/>
 </FrameLayout>
 <!--指针-->
 <ImageView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:src="@mipmap/needle"
 android:layout_gravity="center_horizontal"
 android:layout_marginLeft="@dimen/needleMarginSize"/>
</FrameLayout>

上面的xml,是这个自定义view的一个布局,具体的自定义view的代码如下

package com.musicplaer.eminemmusic.views;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.bumptech.glide.Glide;
import com.musicplaer.eminemmusic.R;
import de.hdodenhof.circleimageview.CircleImageView;
public class PlayMusicView extends FrameLayout {
 private Context mContext;
 private View mView;
 private CircleImageView cv_icon;
 public PlayMusicView(@NonNull Context context) {
 super(context);
 init(context);
 }
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
 super(context, attrs, defStyleAttr, defStyleRes);
 init(context);
 }
 private void init(Context context){
 this.mContext = context;
 mView = LayoutInflater.from(mContext).inflate(R.layout.play_music,this,false);
 cv_icon = mView.findViewById(R.id.cv_icon);
 addView(mView);
 }
 /**
 * 设置光盘中显示的音乐封面图片
 */
 public void setMusicIcon(String icon){
 Glide.with(mContext)
 .load(icon)
 .into(cv_icon);
 }
 public void setMusicIcon(int album1) {
 cv_icon.setImageResource(album1);
 }
}

然后将该自定义的view添加到原先的布局文件中,在Activity中调用setMusicIcon来设置图片,效果如下:

5.设置动画(@integers/xxxx是在app/src/main/res/values/integers.xml中自定义的变量)

(1) 光盘转动动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/linear_interpolator">
 <!--转动效果-->
 <rotate
 android:fromDegrees="0"
 android:toDegrees="360"
 android:pivotX="50%"
 android:pivotY="50%"
 android:duration="@integer/play_music_anim_duration"
 android:repeatCount="infinite"/>
</set>

(2) 指针指向光盘动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/linear_interpolator">
 <!--指针旋转动画-->
 <rotate
 android:fromDegrees="-20"
 android:toDegrees="0"
 android:pivotX="0"
 android:pivotY="0"
 android:duration="@integer/play_needle_anim_duration"
 />
</set>

(3) 指针离开光盘动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:interpolator="@android:anim/linear_interpolator"
 android:fillAfter="true">
 <rotate
 android:fromDegrees="0"
 android:toDegrees="-20"
 android:pivotY="0"
 android:pivotX="0"
 android:duration="@integer/play_needle_anim_duration"
 />
</set>

(4) 在自定义View中设置动画,且在播放Activity中还要调用playMusic()的方法,使得一开始就有动画效果

package com.musicplaer.eminemmusic.views;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.musicplaer.eminemmusic.R;
import de.hdodenhof.circleimageview.CircleImageView;
public class PlayMusicView extends FrameLayout {
 private Context mContext;
 private View mView;
 private CircleImageView cv_icon;
 private Animation mPlayMusicAnim,mPlayNeedleAnim,mStopNeedleAnim;
 private FrameLayout fl_disc;
 private ImageView iv_needle,iv_play;
 private boolean isPlay;
 public PlayMusicView(@NonNull Context context) {
 super(context);
 init(context);
 }
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 public PlayMusicView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
 super(context, attrs, defStyleAttr, defStyleRes);
 init(context);
 }
 private void init(Context context){
 this.mContext = context;
 mView = LayoutInflater.from(mContext).inflate(R.layout.play_music,this,false);
 cv_icon = mView.findViewById(R.id.cv_icon);
 iv_play = mView.findViewById(R.id.iv_play);
 fl_disc = mView.findViewById(R.id.fl_fisc);
 iv_needle = mView.findViewById(R.id.iv_needle);
 //设置监听事件
 fl_disc.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 trigger();
 }
 });
 /**
 * 定义所需要执行的动画:
 * 1,光盘转动的动画
 * 2.指针指向光盘的动画
 * 3.指针离开光盘的动画
 * 使用startAnimation
 */
 //初始化
 mPlayMusicAnim = AnimationUtils.loadAnimation(mContext,R.anim.play_music_animation);
 mPlayNeedleAnim = AnimationUtils.loadAnimation(mContext,R.anim.play_needle_anim);
 mStopNeedleAnim = AnimationUtils.loadAnimation(mContext,R.anim.stao_needle_anim);
 addView(mView);
 }
 /**
 * 设置光盘中显示的音乐封面图片
 */
 public void setMusicIcon(String icon){
 Glide.with(mContext)
 .load(icon)
 .into(cv_icon);
 }
 public void setMusicIcon(int album1) {
 cv_icon.setImageResource(album1);
 }
 /**
 * 播放音乐:设置动画执行效果
 */
 public void playMusic(){
 isPlay = true;
 fl_disc.startAnimation(mPlayMusicAnim);
 iv_needle.startAnimation(mPlayNeedleAnim);
 }
 /**
 * 停止音乐:设置动画执行效果
 */
 private void stopMusic(){
 isPlay = false;
 fl_disc.clearAnimation();
 iv_needle.startAnimation(mStopNeedleAnim);
 //显示按钮
 iv_play.setVisibility(View.VISIBLE);
 }
 /**
 * 切换播放状态
 */
 private void trigger(){
 if(isPlay){
 stopMusic();
 }else {
 playMusic();
 }
 }
}

最后

如果你看到了这里,觉得文章写得不错就给个小赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

Android架构师之路很漫长,一起共勉吧!