Android動畫 播放暫停
目錄

Android 開始暫停動畫.png
效果
國際慣例,先放效果

動畫開始暫停.gif
前言
之前寫了java執行緒的暫停和繼續,Android
下載暫停,圓形下載進度條,相信大家看了上面的動畫效果就知道我這一個系列是要做什麼了,哈哈,沒錯就是一個簡單的網路下載暫停,只是通過一部分一部分的分析,今天把動畫給搞定了,過段時間就是可以成功的把這些整合起來,預計效果就是我們手機應用商城中的軟體下載的效果,可以暫停,也是圓形進度條;擁有開始和暫停的動畫;想想就非常不錯;666666666
正文
自定義View PlayPauseView
-
上面的動畫就是兩個矩形,變成三角形,我們只用設定左邊矩形的四個點的座標,那麼右邊的座標,可以通過自己定義的兩個矩形之間的寬度,算出相應的座標,
-
Path
方法就是用畫筆畫出相應的動畫效果,path.moveTo(),就是從起點畫到後面的點, -
path.lineTo()
畫直線,通過兩個點確定一個直線,就可以成功的畫出動畫, -
path.close()
這可不是關閉方法,而是把線段封閉掉,什麼意思呢?我們花了四個點,但是隻連線了三個線,那麼就會把開始的點和最後的點連線起來,這樣就形成了矩形。
public class PlayPauseView extends View { private int mWidth; //View寬度 private int mHeight; //View高度 private Paint mPaint; private Path mLeftPath; //暫停時左側豎條Path private Path mRightPath; //暫停時右側豎條Path private float mGapWidth; //兩個暫停豎條中間的空隙,預設為兩側豎條的寬度 private float mProgress; //動畫Progress private Rect mRect; private boolean isPlaying; private float mRectWidth;//圓內矩形寬度 private float mRectHeight; //圓內矩形高度 private float mRectLT;//矩形左側上側座標 private float mRadius;//圓的半徑 private int mBgColor = Color.WHITE; private int mBtnColor = Color.BLACK; private int mDirection = Direction.POSITIVE.value; private float mPadding; private int mAnimDuration = 200;//動畫時間 public PlayPauseView(Context context) { super(context); } public PlayPauseView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public PlayPauseView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context, AttributeSet attrs) { mPaint = new Paint(); mPaint.setAntiAlias(true); mLeftPath = new Path(); mRightPath = new Path(); mRect = new Rect(); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PlayPauseView); mBgColor = ta.getColor(R.styleable.PlayPauseView_bg_color, Color.WHITE); mBtnColor = ta.getColor(R.styleable.PlayPauseView_btn_color, Color.BLACK); mGapWidth = ta.getDimensionPixelSize(R.styleable.PlayPauseView_gap_width, dp2px(context, 0)); mPadding = ta.getDimensionPixelSize(R.styleable.PlayPauseView_space_padding, dp2px(context, 0)); mDirection = ta.getInt(R.styleable.PlayPauseView_anim_direction, Direction.POSITIVE.value); mAnimDuration = ta.getInt(R.styleable.PlayPauseView_anim_duration, 200); ta.recycle(); setLayerType(View.LAYER_TYPE_SOFTWARE, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { mWidth = Math.min(mWidth, mHeight); } else { mWidth = dp2px(getContext(), 50); } if (heightMode == MeasureSpec.EXACTLY) { mHeight = Math.min(mWidth, mHeight); } else { mHeight = dp2px(getContext(), 50); } mWidth = mHeight = Math.min(mWidth, mHeight); setMeasuredDimension(mWidth, mHeight); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = mHeight = w; initValue(); } private void initValue() { mRadius = mWidth / 2; mPadding = getSpacePadding() == 0 ? mRadius / 3f : getSpacePadding(); if (getSpacePadding() > mRadius / Math.sqrt(2) || mPadding < 0) { mPadding = mRadius / 3f; //預設值 } float space = (float) (mRadius / Math.sqrt(2) - mPadding); //矩形寬高的一半 mRectLT = mRadius - space; float rectRB = mRadius + space; mRectWidth = 2 * space; mRectHeight = 2 * space; mGapWidth = getGapWidth() != 0 ? getGapWidth() : mRectWidth / 3; mProgress = isPlaying ? 0 : 1; mAnimDuration = getAnimDuration() < 0 ? 200 : getAnimDuration(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mLeftPath.rewind(); mRightPath.rewind(); mPaint.setColor(mBgColor); canvas.drawCircle(mWidth / 2, mHeight / 2, mRadius, mPaint); float distance = mGapWidth * (1 - mProgress);//暫停時左右兩邊矩形距離 float barWidth = mRectWidth / 2 - distance / 2;//一個矩形的寬度 float leftLeftTop = barWidth * mProgress;//左邊矩形左上角 float rightLeftTop = barWidth + distance;//右邊矩形左上角 float rightRightTop = 2 * barWidth + distance;//右邊矩形右上角 float rightRightBottom = rightRightTop - barWidth * mProgress; //右邊矩形右下角 mPaint.setColor(mBtnColor); mPaint.setStyle(Paint.Style.FILL); if (mDirection == Direction.NEGATIVE.value) { mLeftPath.moveTo(mRectLT, mRectLT); mLeftPath.lineTo(leftLeftTop + mRectLT, mRectHeight + mRectLT); mLeftPath.lineTo(barWidth + mRectLT, mRectHeight + mRectLT); mLeftPath.lineTo(barWidth + mRectLT, mRectLT); mLeftPath.close(); mRightPath.moveTo(rightLeftTop + mRectLT, mRectLT); mRightPath.lineTo(rightLeftTop + mRectLT, mRectHeight + mRectLT); mRightPath.lineTo(rightRightBottom + mRectLT, mRectHeight + mRectLT); mRightPath.lineTo(rightRightTop + mRectLT, mRectLT); mRightPath.close(); } else { mLeftPath.moveTo(leftLeftTop + mRectLT, mRectLT); mLeftPath.lineTo(mRectLT, mRectHeight + mRectLT); mLeftPath.lineTo(barWidth + mRectLT, mRectHeight + mRectLT); mLeftPath.lineTo(barWidth + mRectLT, mRectLT); mLeftPath.close(); mRightPath.moveTo(rightLeftTop + mRectLT, mRectLT); mRightPath.lineTo(rightLeftTop + mRectLT, mRectHeight + mRectLT); mRightPath.lineTo(rightLeftTop + mRectLT + barWidth, mRectHeight + mRectLT); mRightPath.lineTo(rightRightBottom + mRectLT, mRectLT); mRightPath.close(); } canvas.save(); canvas.translate(mRectHeight / 8f * mProgress, 0); float progress = isPlaying ? (1 - mProgress) : mProgress; int corner = mDirection == Direction.NEGATIVE.value ? -90 : 90; float rotation = isPlaying ? corner * (1 + progress) : corner * progress; canvas.rotate(rotation, mWidth / 2f, mHeight / 2f); canvas.drawPath(mLeftPath, mPaint); canvas.drawPath(mRightPath, mPaint); canvas.restore(); } public ValueAnimator getPlayPauseAnim() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(isPlaying ? 1 : 0, isPlaying ? 0 : 1); valueAnimator.setDuration(mAnimDuration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mProgress = (float) animation.getAnimatedValue(); invalidate(); } }); return valueAnimator; } public void play() { if (getPlayPauseAnim() != null) { getPlayPauseAnim().cancel(); } setPlaying(true); getPlayPauseAnim().start(); } public void pause() { if (getPlayPauseAnim() != null) { getPlayPauseAnim().cancel(); } setPlaying(false); getPlayPauseAnim().start(); } private PlayPauseListener mPlayPauseListener; public void setPlayPauseListener(PlayPauseListener playPauseListener) { mPlayPauseListener = playPauseListener; setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (isPlaying()) { pause(); if (null != mPlayPauseListener) { mPlayPauseListener.pause(); } } else { play(); if (null != mPlayPauseListener) { mPlayPauseListener.play(); } } } }); } public interface PlayPauseListener { void play(); void pause(); } public int dp2px(Context context, float dpVal) { float density = context.getResources().getDisplayMetrics().density; return (int) (density * dpVal + 0.5f); } /* ------------下方是引數------------- */ public boolean isPlaying() { return isPlaying; } public void setPlaying(boolean playing) { isPlaying = playing; } public void setGapWidth(float gapWidth) { mGapWidth = gapWidth; } public float getGapWidth() { return mGapWidth; } public int getBgColor() { return mBgColor; } public int getBtnColor() { return mBtnColor; } public int getDirection() { return mDirection; } public void setBgColor(int bgColor) { mBgColor = bgColor; } public void setBtnColor(int btnColor) { mBtnColor = btnColor; } public void setDirection(Direction direction) { mDirection = direction.value; } public float getSpacePadding() { return mPadding; } public void setSpacePadding(float padding) { mPadding = padding; } public int getAnimDuration() { return mAnimDuration; } public void setAnimDuration(int animDuration) { mAnimDuration = animDuration; } public enum Direction { POSITIVE(1),//順時針 NEGATIVE(2);//逆時針 int value; Direction(int value) { this.value = value; } } }
mBgColor = ta.getColor(R.styleable.PlayPauseView_bg_color, Color.WHITE); mBtnColor = ta.getColor(R.styleable.PlayPauseView_btn_color, Color.BLACK); mGapWidth = ta.getDimensionPixelSize(R.styleable.PlayPauseView_gap_width, dp2px(context, 0)); mPadding = ta.getDimensionPixelSize(R.styleable.PlayPauseView_space_padding, dp2px(context, 0)); mDirection = ta.getInt(R.styleable.PlayPauseView_anim_direction, Direction.POSITIVE.value); mAnimDuration = ta.getInt(R.styleable.PlayPauseView_anim_duration, 200);
大家可能不太清楚這些是什麼,其實這個就是我們在xml
中聲名的屬性,也就是自定義View
的屬性;
自定義xml attrs.xml
<resources> <declare-styleable name="PlayPauseView"> <attr name="bg_color" format="color"/> <attr name="btn_color" format="color"/> <attr name="gap_width" format="dimension|reference"/> <attr name="space_padding" format="dimension|reference"/> <attr name="anim_duration" format="integer"/> <attr name="anim_direction"> <enum name="positive" value="1"/> <enum name="negative" value="2"/> </attr> </declare-styleable> </resources>
大家看到上面的name
,就是我們在自定義View
中的屬性方法;
通過相應的設定,大家就可以看出來了;
介面 activity_main.xml
<LinearLayout 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" android:orientation="vertical" tools:context="com.freedom.lauzy.playpauseview.MainActivity"> <com.freedom.lauzy.playpauseviewlib.PlayPauseView android:id="@+id/play_pause_view1" android:layout_width="80dp" android:layout_height="80dp" android:layout_gravity="center" android:layout_marginTop="40dp" app:anim_direction="positive" app:anim_duration="300" app:bg_color="#E0E0E0" app:btn_color="#000000"/> </LinearLayout>
看見上面的app:
後下面跟的屬性名稱了嗎?就是我們自定義View
的那些屬性,我們是在自定義的時候通過get()``set()
方法,設定屬性的;
主方法 MainActivity()
package com.freedom.lauzy.playpauseview; import android.graphics.Color; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; import com.freedom.lauzy.playpauseviewlib.PlayPauseView; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final PlayPauseView playPauseView1 = (PlayPauseView) findViewById(R.id.play_pause_view1); playPauseView1.setPlayPauseListener(new PlayPauseView.PlayPauseListener() { @Override public void play() { Toast.makeText(MainActivity.this, "Play", Toast.LENGTH_SHORT).show(); } @Override public void pause() { Toast.makeText(MainActivity.this, "Pause", Toast.LENGTH_SHORT).show(); } }); } }
這個就還是蠻簡單的,設定一下點選事件就可以了,我們自定義的時候,自定義了點選事件(可以看看上面的程式碼)。
總結
自定義View時,要想一想我們自定義需要什麼功能,他有動畫嗎,需要什麼樣的引數,可設定的屬性有需要多少,需要動畫嗎?需要什麼要的動畫,等等
- 首先就是兩個矩形,先考慮如果畫出兩個矩形,先畫出一個圓,配置該檢視的寬高,就像畫出個圓形,在圓形裡面畫出矩形,左邊矩形的座標,如果畫,兩個矩形的寬度設定出來,就知道相應的右邊的座標,這樣子兩個矩形就出來了
- 其次就是個三角形,也就是三個點的座標,通過寬度換算成適合的大小,畫出即可;
- 最後就是動畫,設定動畫時間,動畫效果
- 最後就是可配置的引數和屬性;
感謝
感謝大家!!! 加油!!! 努力!! 日更!!