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

先看效果,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



  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值