Android仿酷狗音樂的啟動(dòng)頁倒計(jì)時(shí)效果
今天介紹一個(gè)很簡單的倒計(jì)時(shí)動(dòng)畫,仿酷狗音樂的啟動(dòng)頁倒計(jì)時(shí)效果,也是大多數(shù)APP在用的一個(gè)動(dòng)畫,來看看效果圖:

整體的思路就是用一個(gè)平滑的幀動(dòng)畫來畫圓弧就行了。
這篇文章學(xué)到什么?
了解屬性動(dòng)畫ValueAnimator的用法
了解動(dòng)畫屬性插值Interpolator,讓動(dòng)畫過度得更自然
如何畫圓弧
開始準(zhǔn)備
新建一個(gè)類繼承TextView,因?yàn)橹虚g還有跳過的文本,所以選擇用TextView來畫個(gè)動(dòng)起來的背景圖。
/*** 倒計(jì)時(shí)文本*/@SuppressLint("AppCompatCustomView")public class CountDownTextView extends TextView {// 倒計(jì)時(shí)動(dòng)畫時(shí)間private int duration = 5000;// 動(dòng)畫掃過的角度private int mSweepAngle = 360;// 屬性動(dòng)畫private ValueAnimator animator;// 矩形用來保存位置大小信息private final RectF mRect = new RectF();// 圓弧的畫筆private Paint mBackgroundPaint;public CountDownTextView(Context context) {this(context, null);}public CountDownTextView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CountDownTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {// 設(shè)置畫筆平滑mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 設(shè)置畫筆顏色mBackgroundPaint.setColor(Color.WHITE);// 設(shè)置畫筆邊框?qū)挾?/span>mBackgroundPaint.setStrokeWidth(5);// 設(shè)置畫筆樣式為邊框類型mBackgroundPaint.setStyle(Paint.Style.STROKE);}}
開始動(dòng)畫
原理:利用圓的360度角來做屬性動(dòng)畫,讓它平滑的分配做每幀動(dòng)畫的角度值,然后調(diào)用invalidate()來重繪自己本身,從而進(jìn)入到本身的onDraw()方法來畫圖。
/*** 開始倒計(jì)時(shí)*/public void start() {// 在動(dòng)畫中if (mSweepAngle != 360) return;// 初始化屬性動(dòng)畫animator = ValueAnimator.ofInt(mSweepAngle).setDuration(duration);// 設(shè)置插值animator.setInterpolator(new LinearInterpolator());// 設(shè)置動(dòng)畫監(jiān)聽animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// 獲取屬性動(dòng)畫返回的動(dòng)畫值mSweepAngle = (int) animation.getAnimatedValue();// 重繪自己invalidate();}});// 開始動(dòng)畫animator.start();}
畫圓弧
畫圓弧比較簡單, 從效果圖來看,有的同學(xué)可能剛開始以為要畫兩個(gè)圓,一個(gè)背景的內(nèi)圓和一個(gè)白色邊框的大圓,其實(shí)這里可以利用畫筆設(shè)置畫筆樣式paint.setStyle()和寬度大小paint.setStrokeWidth()的特性來實(shí)現(xiàn)。代碼很簡單,開始的角度選擇-90,從頭頂開始畫。這樣實(shí)現(xiàn)的是一個(gè)順時(shí)針的倒計(jì)時(shí)效果。如果你想實(shí)現(xiàn)酷狗的逆時(shí)針效果,就控制mSweepAngle的值用mSweepAngle = 360 - mSweepAngle開始就可以了。
@Overrideprotected void onDraw(Canvas canvas) {int padding = dp2px(4);mRect.top = padding;mRect.left = padding;mRect.right = getWidth() - padding;mRect.bottom = getHeight() - padding;// 畫倒計(jì)時(shí)線內(nèi)圓canvas.drawArc(mRect, //弧線所使用的矩形區(qū)域大小-90, //開始角度mSweepAngle, //掃過的角度false, //是否使用中心mBackgroundPaint); // 設(shè)置畫筆super.onDraw(canvas);}
什么是插值動(dòng)畫?
為了讓動(dòng)畫過度的更加自然或者添加一些動(dòng)畫效果,比如勻速運(yùn)動(dòng)、加速運(yùn)動(dòng)、減速運(yùn)動(dòng)、彈跳運(yùn)動(dòng)等等,這些的動(dòng)畫的效果就是靠插值來實(shí)現(xiàn)的。在Android中系統(tǒng)內(nèi)置了一些插值,更加直觀的展示下面介紹的動(dòng)畫效果。
| 插值 | 說明 |
|---|---|
| LinearInterpolator | 以常量速率改變 |
| BounceInterpolator | 動(dòng)畫結(jié)束的時(shí)候彈起 |
| CycleInterpolator | 動(dòng)畫循環(huán)播放特定的次數(shù),速率改變沿著正弦曲線 |
| DecelerateInterpolator | 在動(dòng)畫開始的地方快然后慢 |
| OvershootInterpolator | 向前甩一定值后再回到原來位置 |
| AccelerateInterpolator | 在動(dòng)畫開始的地方速率改變比較慢,然后開始加速 |
| AnticipateInterpolator | 開始的時(shí)候向后然后向前甩 |
| AccelerateDecelerateInterpolator | 在動(dòng)畫開始與介紹的地方速率改變比較慢,在中間的時(shí)候加速 |
| AnticipateOvershootInterpolator | 開始的時(shí)候向后然后向前甩一定值后返回最后的值 |
項(xiàng)目使用
這里要定義文本的寬高,因?yàn)闆]有畫底部的黑色圓背景,還要設(shè)置一下背景圖。
<com.example.viewdemo.CountDownTextViewandroid:id="@+id/tv_skip"style="@style/Widget.AppCompat.Button.Borderless"android:layout_width="40dp"android:layout_height="40dp"android:layout_gravity="center"android:background="@drawable/bg_count_down"android:text="跳過"android:textColor="#ffffff"android:textSize="12sp"android:visibility="visible" />
背景圖
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_pressed="true"><shape android:shape="oval"><solid android:color="#302d2d2d" /></shape></item><item><shape android:shape="oval"><solid android:color="#7F2d2d2d" /></shape></item></selector>
完整代碼
/*** 倒計(jì)時(shí)文本*/("AppCompatCustomView")public class CountDownTextView extends TextView {// 倒計(jì)時(shí)動(dòng)畫時(shí)間private int duration = 5000;// 動(dòng)畫掃過的角度private int mSweepAngle = 360;// 屬性動(dòng)畫private ValueAnimator animator;// 矩形用來保存位置大小信息private final RectF mRect = new RectF();// 圓弧的畫筆private Paint mBackgroundPaint;public CountDownTextView(Context context) {this(context, null);}public CountDownTextView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CountDownTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}protected void onDraw(Canvas canvas) {int padding = 5;mRect.top = padding;mRect.left = padding;mRect.right = getWidth() - padding;mRect.bottom = getHeight() - padding;// 畫倒計(jì)時(shí)線內(nèi)圓canvas.drawArc(mRect, //弧線所使用的矩形區(qū)域大小-90, //開始角度mSweepAngle, //掃過的角度false, //是否使用中心mBackgroundPaint); // 設(shè)置畫筆start();super.onDraw(canvas);}private void init() {// 設(shè)置畫筆平滑mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 設(shè)置畫筆顏色mBackgroundPaint.setColor(Color.WHITE);// 設(shè)置畫筆邊框?qū)挾?/span>mBackgroundPaint.setStrokeWidth(5);// 設(shè)置畫筆樣式為邊框類型mBackgroundPaint.setStyle(Paint.Style.STROKE);}/*** 開始倒計(jì)時(shí)*/public void start() {// 在動(dòng)畫中if (mSweepAngle != 360) return;// 初始化屬性動(dòng)畫animator = ValueAnimator.ofInt(mSweepAngle).setDuration(duration);// 設(shè)置插值animator.setInterpolator(new LinearInterpolator());// 設(shè)置動(dòng)畫監(jiān)聽animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {// 獲取屬性動(dòng)畫返回的動(dòng)畫值mSweepAngle = (int) animation.getAnimatedValue();// 重繪自己invalidate();}});// 開始動(dòng)畫animator.start();}}
到這里就結(jié)束啦.
