|
|
package com.example.musicplayer.widget;
|
|
|
|
|
|
import android.animation.Animator;
|
|
|
import android.animation.ObjectAnimator;
|
|
|
import android.animation.ValueAnimator;
|
|
|
import android.content.Context;
|
|
|
import android.graphics.Bitmap;
|
|
|
import android.graphics.BitmapFactory;
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
import android.graphics.drawable.LayerDrawable;
|
|
|
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
|
|
|
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
|
|
|
import android.util.AttributeSet;
|
|
|
import android.view.View;
|
|
|
import android.view.animation.AccelerateInterpolator;
|
|
|
import android.view.animation.LinearInterpolator;
|
|
|
import android.widget.ImageView;
|
|
|
import android.widget.RelativeLayout;
|
|
|
|
|
|
import com.example.musicplayer.R;
|
|
|
import com.example.musicplayer.util.CommonUtil;
|
|
|
import com.example.musicplayer.util.DisplayUtil;
|
|
|
|
|
|
/**
|
|
|
* Created by 残渊 on 2018/10/27.
|
|
|
*/
|
|
|
|
|
|
public class DiscView extends RelativeLayout {
|
|
|
|
|
|
private ImageView mIvNeedle;
|
|
|
private ObjectAnimator mNeedleAnimator;
|
|
|
|
|
|
|
|
|
private ObjectAnimator mObjectAnimator;
|
|
|
/*标记ViewPager是否处于偏移的状态*/
|
|
|
private boolean mViewPagerIsOffset = false;
|
|
|
|
|
|
/*标记唱针复位后,是否需要重新偏移到唱片处*/
|
|
|
private boolean mIsNeed2StartPlayAnimator = false;
|
|
|
private MusicStatus musicStatus = MusicStatus.STOP;
|
|
|
|
|
|
public static final int DURATION_NEEDLE_ANIAMTOR = 500;
|
|
|
private NeedleAnimatorStatus needleAnimatorStatus = NeedleAnimatorStatus.IN_FAR_END;
|
|
|
|
|
|
|
|
|
private int mScreenWidth, mScreenHeight;
|
|
|
|
|
|
|
|
|
/*唱针当前所处的状态*/
|
|
|
private enum NeedleAnimatorStatus {
|
|
|
/*移动时:从唱盘往远处移动*/
|
|
|
TO_FAR_END,
|
|
|
/*移动时:从远处往唱盘移动*/
|
|
|
TO_NEAR_END,
|
|
|
/*静止时:离开唱盘*/
|
|
|
IN_FAR_END,
|
|
|
/*静止时:贴近唱盘*/
|
|
|
IN_NEAR_END
|
|
|
}
|
|
|
|
|
|
/*音乐当前的状态:只有播放、暂停、停止三种*/
|
|
|
public enum MusicStatus {
|
|
|
PLAY, PAUSE, STOP
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public DiscView(Context context) {
|
|
|
this(context, null);
|
|
|
}
|
|
|
|
|
|
public DiscView(Context context, AttributeSet attrs) {
|
|
|
this(context, attrs, 0);
|
|
|
}
|
|
|
|
|
|
public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
|
super(context, attrs, defStyleAttr);
|
|
|
mScreenWidth = CommonUtil.getScreenWidth(context);
|
|
|
mScreenHeight = CommonUtil.getScreenHeight(context);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
protected void onFinishInflate() {
|
|
|
super.onFinishInflate();
|
|
|
|
|
|
initDiscImg();
|
|
|
initNeedle();
|
|
|
initObjectAnimator();
|
|
|
}
|
|
|
|
|
|
private void initDiscImg() {
|
|
|
ImageView mDiscBackground = findViewById(R.id.iv_disc_background);
|
|
|
mObjectAnimator=getDiscObjectAnimator(mDiscBackground);
|
|
|
mDiscBackground.setImageDrawable(getDiscDrawable(
|
|
|
BitmapFactory.decodeResource(getResources(),R.drawable.default_disc)
|
|
|
));
|
|
|
|
|
|
|
|
|
int marginTop = (int) (DisplayUtil.SCALE_DISC_MARGIN_TOP * mScreenHeight);
|
|
|
LayoutParams layoutParams = (LayoutParams) mDiscBackground
|
|
|
.getLayoutParams();
|
|
|
layoutParams.setMargins(0, marginTop, 0, 0);
|
|
|
|
|
|
mDiscBackground.setLayoutParams(layoutParams);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void initNeedle() {
|
|
|
mIvNeedle = findViewById(R.id.iv_needle);
|
|
|
|
|
|
int needleWidth = (int) (DisplayUtil.SCALE_NEEDLE_WIDTH * mScreenWidth);
|
|
|
int needleHeight = (int) (DisplayUtil.SCALE_NEEDLE_HEIGHT * mScreenHeight);
|
|
|
|
|
|
/*设置手柄的外边距为负数,让其隐藏一部分*/
|
|
|
int marginTop = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_TOP * mScreenHeight) * -1;
|
|
|
int marginLeft = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_LEFT * mScreenWidth);
|
|
|
|
|
|
Bitmap originBitmap = BitmapFactory.decodeResource(getResources(), R.drawable
|
|
|
.ic_needle);
|
|
|
Bitmap bitmap = Bitmap.createScaledBitmap(originBitmap, needleWidth, needleHeight, false);
|
|
|
|
|
|
LayoutParams layoutParams = (LayoutParams) mIvNeedle.getLayoutParams();
|
|
|
layoutParams.setMargins(marginLeft, marginTop, 0, 0);
|
|
|
|
|
|
int pivotX = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_X * mScreenWidth);
|
|
|
int pivotY = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_Y * mScreenWidth);
|
|
|
|
|
|
mIvNeedle.setPivotX(pivotX);
|
|
|
mIvNeedle.setPivotY(pivotY);
|
|
|
mIvNeedle.setRotation(DisplayUtil.ROTATION_INIT_NEEDLE);
|
|
|
mIvNeedle.setImageBitmap(bitmap);
|
|
|
mIvNeedle.setLayoutParams(layoutParams);
|
|
|
}
|
|
|
|
|
|
private void initObjectAnimator() {
|
|
|
mNeedleAnimator = ObjectAnimator.ofFloat(mIvNeedle, View.ROTATION, DisplayUtil
|
|
|
.ROTATION_INIT_NEEDLE, 0);
|
|
|
mNeedleAnimator.setDuration(DURATION_NEEDLE_ANIAMTOR);
|
|
|
mNeedleAnimator.setInterpolator(new AccelerateInterpolator());
|
|
|
mNeedleAnimator.addListener(new Animator.AnimatorListener() {
|
|
|
@Override
|
|
|
public void onAnimationStart(Animator animator) {
|
|
|
/**
|
|
|
* 根据动画开始前NeedleAnimatorStatus的状态,
|
|
|
* 即可得出动画进行时NeedleAnimatorStatus的状态
|
|
|
* */
|
|
|
if (needleAnimatorStatus == NeedleAnimatorStatus.IN_FAR_END) {
|
|
|
needleAnimatorStatus = NeedleAnimatorStatus.TO_NEAR_END;
|
|
|
} else if (needleAnimatorStatus == NeedleAnimatorStatus.IN_NEAR_END) {
|
|
|
needleAnimatorStatus = NeedleAnimatorStatus.TO_FAR_END;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAnimationEnd(Animator animator) {
|
|
|
|
|
|
if (needleAnimatorStatus == NeedleAnimatorStatus.TO_NEAR_END) {
|
|
|
needleAnimatorStatus = NeedleAnimatorStatus.IN_NEAR_END;
|
|
|
playDiscAnimator();
|
|
|
musicStatus = MusicStatus.PLAY;
|
|
|
} else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_FAR_END) {
|
|
|
needleAnimatorStatus = NeedleAnimatorStatus.IN_FAR_END;
|
|
|
if (musicStatus == MusicStatus.STOP) {
|
|
|
mIsNeed2StartPlayAnimator = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (mIsNeed2StartPlayAnimator) {
|
|
|
mIsNeed2StartPlayAnimator = false;
|
|
|
/**
|
|
|
* 只有在ViewPager不处于偏移状态时,才开始唱盘旋转动画
|
|
|
* */
|
|
|
if (!mViewPagerIsOffset) {
|
|
|
/*延时500ms*/
|
|
|
DiscView.this.postDelayed(new Runnable() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
playAnimator();
|
|
|
}
|
|
|
}, 50);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAnimationCancel(Animator animator) {
|
|
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public void onAnimationRepeat(Animator animator) {
|
|
|
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 得到唱盘图片
|
|
|
* 唱盘图片由空心圆盘及音乐专辑图片“合成”得到
|
|
|
*/
|
|
|
public Drawable getDiscDrawable(Bitmap bitmap) {
|
|
|
int discSize = (int) (mScreenWidth * DisplayUtil.SCALE_DISC_SIZE);
|
|
|
int musicPicSize = (int) (mScreenWidth * DisplayUtil.SCALE_MUSIC_PIC_SIZE);
|
|
|
|
|
|
Bitmap bitmapDisc = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R
|
|
|
.drawable.ic_disc), discSize, discSize, false);
|
|
|
Bitmap bitmapMusicPic = Bitmap.createScaledBitmap(bitmap, musicPicSize, musicPicSize, true);
|
|
|
BitmapDrawable discDrawable = new BitmapDrawable(bitmapDisc);
|
|
|
RoundedBitmapDrawable roundMusicDrawable = RoundedBitmapDrawableFactory.create
|
|
|
(getResources(), bitmapMusicPic);
|
|
|
|
|
|
//抗锯齿
|
|
|
discDrawable.setAntiAlias(true);
|
|
|
roundMusicDrawable.setAntiAlias(true);
|
|
|
|
|
|
Drawable[] drawables = new Drawable[2];
|
|
|
drawables[0] = roundMusicDrawable;
|
|
|
drawables[1] = discDrawable;
|
|
|
|
|
|
LayerDrawable layerDrawable = new LayerDrawable(drawables);
|
|
|
int musicPicMargin = (int) ((DisplayUtil.SCALE_DISC_SIZE - DisplayUtil
|
|
|
.SCALE_MUSIC_PIC_SIZE) * mScreenWidth / 2);
|
|
|
//调整专辑图片的四周边距,让其显示在正中
|
|
|
layerDrawable.setLayerInset(0, musicPicMargin, musicPicMargin, musicPicMargin,
|
|
|
musicPicMargin);
|
|
|
|
|
|
return layerDrawable;
|
|
|
}
|
|
|
|
|
|
public ObjectAnimator getDiscObjectAnimator(ImageView disc) {
|
|
|
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(disc, View.ROTATION, 0, 360);
|
|
|
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
|
|
|
objectAnimator.setDuration(30 * 1000);
|
|
|
objectAnimator.setInterpolator(new LinearInterpolator());
|
|
|
|
|
|
return objectAnimator;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
protected void onDetachedFromWindow() {
|
|
|
super.onDetachedFromWindow();
|
|
|
}
|
|
|
|
|
|
/*播放动画*/
|
|
|
private void playAnimator() {
|
|
|
/*唱针处于远端时,直接播放动画*/
|
|
|
if (needleAnimatorStatus == NeedleAnimatorStatus.IN_FAR_END) {
|
|
|
mNeedleAnimator.start();
|
|
|
}
|
|
|
/*唱针处于往远端移动时,设置标记,等动画结束后再播放动画*/
|
|
|
else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_FAR_END) {
|
|
|
mIsNeed2StartPlayAnimator = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*暂停动画*/
|
|
|
private void pauseAnimator() {
|
|
|
/*播放时暂停动画*/
|
|
|
if (needleAnimatorStatus == NeedleAnimatorStatus.IN_NEAR_END) {
|
|
|
pauseDiscAnimatior();
|
|
|
}
|
|
|
/*唱针往唱盘移动时暂停动画*/
|
|
|
else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_NEAR_END) {
|
|
|
mNeedleAnimator.reverse();
|
|
|
/**
|
|
|
* 若动画在没结束时执行reverse方法,则不会执行监听器的onStart方法,此时需要手动设置
|
|
|
* */
|
|
|
needleAnimatorStatus = NeedleAnimatorStatus.TO_FAR_END;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/*播放唱盘动画*/
|
|
|
private void playDiscAnimator() {
|
|
|
if (mObjectAnimator.isPaused()) {
|
|
|
mObjectAnimator.resume();
|
|
|
} else {
|
|
|
mObjectAnimator.start();
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/*暂停唱盘动画*/
|
|
|
private void pauseDiscAnimatior() {
|
|
|
|
|
|
mObjectAnimator.pause();
|
|
|
mNeedleAnimator.reverse();
|
|
|
}
|
|
|
|
|
|
|
|
|
public void play() {
|
|
|
playAnimator();
|
|
|
}
|
|
|
|
|
|
public void pause() {
|
|
|
musicStatus = MusicStatus.PAUSE;
|
|
|
pauseAnimator();
|
|
|
}
|
|
|
|
|
|
public void stop() {
|
|
|
musicStatus = MusicStatus.STOP;
|
|
|
pauseAnimator();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void next() {
|
|
|
playAnimator();
|
|
|
selectMusicWithButton();
|
|
|
}
|
|
|
|
|
|
public void last() {
|
|
|
playAnimator();
|
|
|
selectMusicWithButton();
|
|
|
}
|
|
|
|
|
|
public boolean isPlaying() {
|
|
|
return musicStatus == MusicStatus.PLAY;
|
|
|
}
|
|
|
|
|
|
private void selectMusicWithButton() {
|
|
|
if (musicStatus == MusicStatus.PLAY) {
|
|
|
mIsNeed2StartPlayAnimator = true;
|
|
|
pauseAnimator();
|
|
|
} else if (musicStatus == MusicStatus.PAUSE) {
|
|
|
play();
|
|
|
}
|
|
|
}
|
|
|
}
|