仿网易云音乐播放器(磁盘转圈背景虚化等等)

Posted jzdwajue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仿网易云音乐播放器(磁盘转圈背景虚化等等)相关的知识,希望对你有一定的参考价值。

先看效果,CSDN的git传上去总是不动。不知道为什么。

技术分享


主要思路:

1 、 除了 開始/暂停 、上一首、下一首 这三个icon。你看到的是一个ViewGroup ,这个ViewGroup里面有圆形封面。黑色圈圈磁盘。唱针,高斯模糊背景图

2、 凝视掉了磁盘一起转动的效果,如今的方案不是最好的,建议若是想实现,能够把圆形封面和磁盘合并成一张图(最好在CicicleImageView这里面做)。给一个旋转动画。两个动画。两个View,帧的频率不会那么高

3、凝视掉了上一首、下一首切换的时候渐变的动画效果,原图从1-0 。新图从0-1 的渐变。 在模拟器上会报错。主要是由于改变ImageView的背景那一行报错。眼下不知道详细原因。好像是底层出现野指针

欢迎大家优化,改动上面的问题。改好一定要跟我交流下。

以下是代码结构:

技术分享


CircleImageView : 生成圆形图片

GaussianBlurUtil : 高斯模糊

MusicPlayView : 播放器View

MainActivity:主控制类


布局2个,一个是主,一个是播放器的View.看下主的就知道思路了。

一个播放器。三个Button

<?

xml version="1.0" encoding="utf-8"?

> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <include layout="@layout/media_play_view" android:id="@+id/layout_media_play_view" /> <Button android:id="@+id/btn_play_pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/fm_btn_play" android:layout_centerInParent="true"/> <Button android:id="@+id/btn_previous" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_play_previous" android:layout_centerVertical="true" android:layout_alignParentLeft="true"/> <Button android:id="@+id/btn_next" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/bg_play_next" android:layout_centerVertical="true" android:layout_alignParentRight="true"/> </RelativeLayout>


播放器源代码,里面注视代码不少。

/**
 * 代码说明: 1. 凝视掉了磁盘一起转动的效果。如今的方案不是最好的,建议若是想实现,能够把圆形封面和磁盘合并成一张图(最好在CicicleImageView这里面做)。

给一个旋转动画。

两个动画。两个View,帧的频率不会那么高 * 2. 凝视掉了上一首、下一首切换的时候渐变的动画效果。原图从1-0 ,新图从0-1 的渐变。

在模拟器上会报错。主要是由于改变ImageView的背景那一行报错。

* @author xiu * */ public class MusicPlayView extends RelativeLayout { private Context mContext; //旋转一周所用时间 private static final int ROTATE_TIME = 12 * 1000; //动画旋转反复运行的次数。这里代表无数次。似乎没有无限运行的属性,所以用了一个大数字代表 private static final int ROTATE_COUNT = 10000; //唱针动画时间 private static final int NEEDLE_TIME = 1 * 500 ; //唱针动画运行的角度 private static final int NEEDLE_RADIUS = 30 ; //封面、背景切换时候的渐变动画 private static final int AVATART_DISC_ALPHA_TIME = 1 * 300 ; private static final float AVATART_DISC_ALPHA_PERCENT = 0.3f; //背景 private ImageView mBackground ; //唱针 private ImageView mNeedle; //唱片 // private ImageView mDisc; //封面 private CircleImageView mAvatar; private boolean isPlay = false; //唱针移动动画 ObjectAnimator mAniNeedle; //磁盘和封面旋转动画 // ObjectAnimator mAniDisc; ObjectAnimator mAniAvatar; // //封面更换时的渐变效果 // ObjectAnimator mAniAlphaAvatarHide; // ObjectAnimator mAniAlphaAvatarShow; // // //背景更换时的渐变效果 // ObjectAnimator mAniAlphaDiscBgHide; // ObjectAnimator mAniAlphaDiscBgShow; float mValueAvatar ; float mValueDisc ; float mValueNeedle ; // private int mCurrentImageResource = 0; // public MusicPlay mMusicPlayListener ; public MusicPlayView(Context context, AttributeSet attrs) { super(context); mContext = context; } public MusicPlayView(Context context) { super(context); mContext = context; } public MusicPlayView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mContext = context; } /*public interface MusicPlay{ void onAvatarChange(); void onDiscbgChange(); }*/ /*public void setMusicPlayerListener(MusicPlay listener ){ this.mMusicPlayListener = listener ; }*/ @Override protected void onFinishInflate() { super.onFinishInflate(); mBackground = (ImageView) findViewById(R.id.bg); mAvatar = (CircleImageView) findViewById(R.id.avatar); // Bitmap conformBitmap = toConformBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.fm_play_disc), mAvatar.getBitmap()); // mAvatar.setImageBitmap(conformBitmap); // mAvatar.setBackgroundDrawable(new BitmapDrawable(conformBitmap)); // mAvatar.setBackgroundDrawable(getResources().getDrawable(R.drawable.fm_play_disc)); // mDisc = (ImageView) findViewById(R.id.disc); mNeedle = (ImageView) findViewById(R.id.needle); // mDisc.setVisibility(View.GONE); initAvatarAnimation(0f); // initDiscAnimation(0f); initNeedleAnimation(0f); // //封面页面动画 // mAniAlphaAvatarHide = ObjectAnimator.ofFloat(mAvatar, "alpha", 1, AVATART_DISC_ALPHA_PERCENT).setDuration(AVATART_DISC_ALPHA_TIME); // mAniAlphaAvatarHide.addListener(avatarAlphaHideListener); // mAniAlphaAvatarShow = ObjectAnimator.ofFloat(mAvatar, "alpha", AVATART_DISC_ALPHA_PERCENT, 1).setDuration(AVATART_DISC_ALPHA_TIME); // // mAniAlphaDiscBgHide = ObjectAnimator.ofFloat(mBackground, "alpha", 1, AVATART_DISC_ALPHA_PERCENT).setDuration(AVATART_DISC_ALPHA_TIME); // mAniAlphaDiscBgHide.addListener(discbgAlphaHideListener); // mAniAlphaDiscBgShow = ObjectAnimator.ofFloat(mBackground, "alpha", AVATART_DISC_ALPHA_PERCENT, 1).setDuration(AVATART_DISC_ALPHA_TIME); } /* AnimatorListener avatarAlphaHideListener = new AnimatorListener() { @Override public void onAnimationStart(Animator arg0) { } @Override public void onAnimationRepeat(Animator arg0) { } @Override public void onAnimationEnd(Animator arg0) { mMusicPlayListener.onAvatarChange(); mAniAlphaAvatarShow.start(); } @Override public void onAnimationCancel(Animator arg0) { } }; AnimatorListener discbgAlphaHideListener = new AnimatorListener() { @Override public void onAnimationStart(Animator arg0) { } @Override public void onAnimationRepeat(Animator arg0) { } @Override public void onAnimationEnd(Animator arg0) { mMusicPlayListener.onDiscbgChange(); mAniAlphaDiscBgShow.start(); } @Override public void onAnimationCancel(Animator arg0) { } };*/ /** * * 设置背景 * @param d */ public void setBackgroundDrawable(Drawable d){ mBackground.setBackgroundDrawable(d); } /** * * 设置背景 * @param d */ public void setBackgroundResource(int resourece){ Bitmap bmp = GaussianBlurUtil.drawableToBitmap(getResources().getDrawable(resourece)) ; mBackground.setBackgroundDrawable(GaussianBlurUtil.BoxBlurFilter(bmp)); } public void setAvatarImageResource(int resourceid){ mAvatar.setImageDrawable(getResources().getDrawable(resourceid)); } /** * 播放 */ public void play(){ initNeedleAnimation(0f); AnimatorSet animSet = new AnimatorSet(); // animSet.playTogether(mAniAvatar,mAniDisc); animSet.play(mAniAvatar).after(mAniNeedle); animSet.start(); setPlay(true); } /** * 暂停 */ public void pause(){ initNeedleAnimation(NEEDLE_RADIUS); mAniNeedle.start(); mAniAvatar.cancel(); // mAniDisc.cancel(); initAvatarAnimation(mValueAvatar); // initDiscAnimation(mValueDisc); setPlay(false); } /** * 下一首 */ public void next(int resourceId){ // mAniAlphaAvatarHide.start(); // mAniAlphaDiscBgHide.start(); changeImage(resourceId); // pause(); // initAvatarAnimation(0f); // initDiscAnimation(0f); // initNeedleAnimation(0f); // play(); } private void changeImage(final int resourceId){ postDelayed(new Runnable() { @Override public void run() { setBackgroundResource(resourceId); setAvatarImageResource(resourceId); } }, 0); } private Bitmap toConformBitmap(Bitmap background, Bitmap foreground) { if( background == null ) { return null; } int bgWidth = background.getWidth(); int bgHeight = background.getHeight(); //int fgWidth = foreground.getWidth(); //int fgHeight = foreground.getHeight(); //create the new blank bitmap 创建一个新的和SRC长度宽度一样的位图 Bitmap newbmp = Bitmap.createBitmap(bgWidth, bgHeight, Config.RGB_565); Canvas cv = new Canvas(newbmp); //draw bg into cv.drawBitmap(background, 0, 0, null);//在 0,0坐标開始画入bg //draw fg into cv.drawBitmap(foreground, 0, 0, null);//在 0,0坐标開始画入fg ,能够从任何位置画入 //save all clip cv.save(Canvas.ALL_SAVE_FLAG);//保存 //store cv.restore();//存储 return newbmp; } /** * 上一首 */ public void previous(int resourceId){ // mAniAlphaAvatarHide.start(); // mAniAlphaDiscBgHide.start(); pause(); changeImage(resourceId); // pause(); // initAvatarAnimation(0f); // initDiscAnimation(0f); // initNeedleAnimation(0f); // play(); } public boolean isPlay() { return isPlay; } public void setPlay(boolean isPlay) { this.isPlay = isPlay; } /** * 初始化旋转封面动画对象 * @param start */ private void initAvatarAnimation(float start){ mAniAvatar = ObjectAnimator.ofFloat(mAvatar, "rotation", start, 360f + start); mAniAvatar.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mValueAvatar = (Float) animation.getAnimatedValue("rotation"); Log.e("", "角度 : "+ mValueAvatar); } }); mAniAvatar.setDuration(ROTATE_TIME); mAniAvatar.setInterpolator(new LinearInterpolator()); mAniAvatar.setRepeatCount(ROTATE_COUNT); } /** * 初始化旋转磁盘动画对象 * @param start */ /*private void initDiscAnimation(float start){ mAniDisc = ObjectAnimator.ofFloat(mDisc, "rotation", start, 360f + start); mAniDisc.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mValueDisc = (Float) animation.getAnimatedValue("rotation"); } }); mAniDisc.setDuration(ROTATE_TIME); mAniDisc.setInterpolator(new LinearInterpolator()); mAniDisc.setRepeatCount(ROTATE_COUNT); }*/ /** * 初始化唱针动画 * @param start */ private void initNeedleAnimation(float start) { mAniNeedle = ObjectAnimator.ofFloat(mNeedle, "rotation", start, NEEDLE_RADIUS-start).setDuration(NEEDLE_TIME); } }



源代码下载:http://download.csdn.net/detail/u013651247/8270811














以上是关于仿网易云音乐播放器(磁盘转圈背景虚化等等)的主要内容,如果未能解决你的问题,请参考以下文章

Vue2仿网易云风格音乐播放器(附源码)

指尖一点歌声来--微信小程序之仿网易云音乐心得

WPF 仿网易云音乐PC端

3.Android高仿网易云音乐-首页复杂发现界面布局和功能

3.Android高仿网易云音乐-首页复杂发现界面布局和功能

3.Android高仿网易云音乐-首页复杂发现界面布局和功能