Android自定義View——從零開始實現可暫停的旋轉動畫效果

版權聲明:本文爲博主原創文章,未經博主容許不得轉載java

系列教程:Android開發之從零開始系列android

源碼:本期內容比較簡單,源碼就直接在文中貼出來了canvas

你們要是看到有錯誤的地方或者有啥好的建議,歡迎留言評論api

前言:你們平時有用過MAKA或者易企秀這些H5模板製做工具嗎,不知道里面有個小細節你們有沒注意到,就是這個音樂小控件app

當咱們點擊這個控件時,它會開始旋轉並播放背景音樂,再次點擊時會重置回初始狀態。相似的旋轉效果在APP中也十分常見,例如一些音樂播放界面中不斷旋轉的音樂碟片ide

其效果會更復雜一些,碟片會隨着音樂的播放、暫停而旋轉或暫停在某個旋轉角度,從暫停恢復到播放時,又會從當前的角度開始不斷地旋轉。本期將教你們如何利用 屬性動畫 ObjectAnimator補間動畫 RotateAnimation 分別實現這一效果工具

本篇只着重於思路和實現步驟,裏面用到的一些知識原理不會很是細地拿來說,若是有不清楚的api或方法能夠在網上搜下相應的資料,確定有大神講得很是清楚的,我這就不獻醜了。本着認真負責的精神我會把相關知識的博文連接也貼出來(其實就是懶不想寫那麼多哈哈),你們能夠自行傳送。爲了照顧第一次閱讀系列博客的小夥伴,本篇有可能會出現一些在以前系列博客就講過的內容,看過的童鞋自行跳過該段便可oop

國際慣例,先上效果圖post


用ObjectAnimator實現

使用屬性動畫來實現這個效果是最簡單的,由於動畫的開始暫停結束從新播放等方法系統都已經爲咱們封裝好了(android 3.0以上開始支持),咱們只須要繼承ImageView而後調用ObjectAnimator的相應方法便可,代碼比較簡單,這裏就直接貼出來了學習

public class MusicButton extends AppCompatImageView {
    private ObjectAnimator objectAnimator;

    public static final int STATE_PLAYING =1;//正在播放
    public static final int STATE_PAUSE =2;//暫停
    public static final int STATE_STOP =3;//中止
    public int state;

    public MusicButton(Context context) {
        super(context);
        init();
    }

    public MusicButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MusicButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        state = STATE_STOP;
        objectAnimator = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f);//添加旋轉動畫,旋轉中心默認爲控件中點
        objectAnimator.setDuration(3000);//設置動畫時間
        objectAnimator.setInterpolator(new LinearInterpolator());//動畫時間線性漸變
        objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
        objectAnimator.setRepeatMode(ObjectAnimator.RESTART);
    }

    public void playMusic(){
        if(state == STATE_STOP){
            objectAnimator.start();//動畫開始
            state = STATE_PLAYING;
        }else if(state == STATE_PAUSE){
            objectAnimator.resume();//動畫從新開始
            state = STATE_PLAYING;
        }else if(state == STATE_PLAYING){
            objectAnimator.pause();//動畫暫停
            state = STATE_PAUSE;
        }
    }

    public void stopMusic(){
        objectAnimator.end();//動畫結束
        state = STATE_STOP;
    }
}
複製代碼

效果如圖


用RotateAnimation實現

RotateAnimation自己並無封裝暫停動畫的方法,因此實現起來會比ObjectAnimator要複雜一些,本着學習研究的態度,沒有困難創造困難也要上,咱們就來分析一下如何使用「原始的」RotateAnimation實現咱們想要的效果

由於RotateAnimation動畫只有開始和結束的方法,因此當咱們點擊暫停按鈕時,須要記錄當前已經旋轉的角度,重繪View並將畫布旋轉以前記錄的角度。再次播放時,由於View的畫布已經旋轉至以前暫停的角度,咱們只須要新建一個動畫從當前角度播放便可,具體代碼以下

public class MusicButton extends AppCompatImageView {
    public static final int STATE_PLAYING =1;//正在播放
    public static final int STATE_PAUSE =2;//暫停
    public static final int STATE_STOP =3;//中止
    public int state;

    private float angle;//記錄RotateAnimation中受插值器數值影響的角度
    private float angle2;//主要用來記錄暫停時停留的角度,即View初始旋轉角度
    private int viewWidth;
    private int viewHeight;
    private MusicAnim musicAnim;

    public MusicButton(Context context) {
        super(context);
        init();
    }

    public MusicButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MusicButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        state = STATE_STOP;
        angle = 0;
        angle2 = 0;
        viewWidth = 0;
        viewHeight = 0;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewWidth = getMeasuredWidth();
        viewHeight = getMeasuredHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.rotate(angle2,viewWidth/2,viewHeight/2);
        super.onDraw(canvas);
    }

    public class MusicAnim extends RotateAnimation{
        public MusicAnim(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
            super(fromDegrees, toDegrees, pivotX, pivotY);
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            angle = interpolatedTime * 360;
        }
    }

    public void playMusic(){
        if(state == STATE_PLAYING){
            angle2 = (angle2 + angle)%360;//能夠取餘也能夠不取,看實際的需求
            musicAnim.cancel();
            state = STATE_PAUSE;
            invalidate();
        }else {
            musicAnim = new MusicAnim(0,360,viewWidth/2,viewHeight/2);
            musicAnim.setDuration(3000);
            musicAnim.setInterpolator(new LinearInterpolator());//動畫時間線性漸變
            musicAnim.setRepeatCount(ObjectAnimator.INFINITE);
            startAnimation(musicAnim);
			state = STATE_PLAYING;
        }
    }

    public void stopMusic(){
        angle2 = 0;
        clearAnimation();
		state = STATE_STOP;
        invalidate();
    }
}
複製代碼

MusicButton的代碼寫完了,下面將按鈕結合音樂播放的代碼貼出來,感興趣的小夥伴能夠看看

mPlayer = MediaPlayer.create(this, R.raw.音樂名);
mPlayer.setLooping(true);

btnMusic = (MusicButton) findViewById(R.id.btn_music);
btnMusic.setOnClickListener(new View.OnClickListener() {//單擊播放或暫停
	@Override
	public void onClick(View v) {
		btnMusic.playMusic();
		try {
			if (mPlayer != null) {
				if (mPlayer.isPlaying()) {
					mPlayer.pause();
				} else {
					mPlayer.start();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
});
btnMusic.setOnLongClickListener(new View.OnLongClickListener() {//長按中止
	@Override
	public boolean onLongClick(View v) {
		try {
			if (mPlayer != null) {
				mPlayer.stop();
				mPlayer.prepare();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		btnMusic.stopMusic();
		return true;//消費此長按事件,再也不向下傳遞
	}
});
複製代碼

至此本篇教程到此結束,若是你們看了感受還不錯麻煩點個贊,大家的支持是我最大的動力~

相關文章
相關標籤/搜索