Android仿360市場下載按鈕
先看一下效果:

無論多復(fù)雜的動(dòng)畫我們都是可以分割成小單元的,然后分步來實(shí)現(xiàn)。這個(gè)動(dòng)畫大概分為收縮,準(zhǔn)備,加載,完成幾個(gè)部分。為此定義一個(gè)枚舉類來描述view的狀態(tài)。
public enum Status { NORMAL, START, PRE, EXPAND, LOAD, END }收縮動(dòng)畫
使用動(dòng)畫不斷改變圓角矩形的寬度,觸發(fā)重繪。代碼如下:
private void initAnim() {Animation animation1 = new Animation() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {mCurrLength = mWidth * (1 - interpolatedTime);if (mCurrLength < mHeight) {mCurrLength = mHeight;clearAnimation();mAngleAnim.start();}invalidate();}};animation1.setDuration(mShrinkDuration);animation1.setInterpolator(new LinearInterpolator());animation1.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {mStatus = Status.START;}@Overridepublic void onAnimationEnd(Animation animation) {}@Overridepublic void onAnimationRepeat(Animation animation) {}});mShrinkAnim = animation1;...}
onDraw中繪制:
if (mStatus == Status.START || mStatus == Status.NORMAL) {float left = (mWidth - mCurrLength) / 2f;float right = (mWidth + mCurrLength) / 2f;float r = mHeight / 2f;canvas.drawRoundRect(new RectF(left, 0, right, mHeight), r, r, mBgPaint);if (mStatus == Status.NORMAL) {Paint.FontMetrics fm = mTextPaint.getFontMetrics();float y = mHeight / 2 + (fm.descent - fm.ascent) / 2 - fm.descent;canvas.drawText("下載", mWidth / 2, y, mTextPaint);}}
準(zhǔn)備動(dòng)畫
此時(shí)旋轉(zhuǎn)動(dòng)畫,是通過canvas繪制背景圓和三個(gè)小圓,然后不斷旋轉(zhuǎn)畫布來實(shí)現(xiàn)的,具體求圓心坐標(biāo)和角度動(dòng)畫我們直接看代碼:
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mAngle += mPreAnimSpeed;invalidate();}});animator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {mStatus = Status.PRE;}@Overridepublic void onAnimationEnd(Animator animation) {mAngleAnim.cancel();startAnimation(mTranslateAnim);}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});animator.setDuration(mPreAnimDuration);animator.setInterpolator(new LinearInterpolator());mAngleAnim = animator;
onDraw中繪制代碼:
if (mStatus == Status.PRE) {canvas.drawCircle(mWidth / 2f, mHeight / 2f, mHeight / 2f, mBgPaint);canvas.save();mTextPaint.setStyle(Paint.Style.FILL);canvas.rotate(mAngle, mWidth / 2, mHeight / 2);//大圓的圓心 半徑float cX = mWidth / 2f;float cY = mHeight / 2f;float radius = mHeight / 2 / 3f;canvas.drawCircle(cX, cY, radius, mTextPaint);//上方小圓的參數(shù)float rr = radius / 2f;float cYY = mHeight / 2 - (radius + rr / 3);canvas.drawCircle(cX, cYY, rr, mTextPaint);//左下小圓參數(shù)float cXX = (float) (cX - Math.sqrt(2) / 2f * (radius + rr / 3f));cYY = (float) (mHeight / 2 + Math.sqrt(2) / 2f * (radius + rr / 3f));canvas.drawCircle(cXX, cYY, rr, mTextPaint);//右下小圓參數(shù)cXX = (float) (cX + Math.sqrt(2) / 2f * (radius + rr / 3f));canvas.drawCircle(cXX, cYY, rr, mTextPaint);canvas.restore();}
展開動(dòng)畫
展開動(dòng)畫也是不斷改變view的寬度并重繪圓角矩形,同時(shí)需要對(duì)準(zhǔn)備動(dòng)畫的狀態(tài)進(jìn)行向右位移。
Animation animator1 = new Animation() {@Overrideprotected void applyTransformation(float interpolatedTime, Transformation t) {mCurrLength = mHeight + (mWidth - mHeight) * interpolatedTime;mTranslationX = (mWidth - mHeight) / 2 * interpolatedTime;invalidate();}};animator1.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {mStatus = Status.EXPAND;}@Overridepublic void onAnimationEnd(Animation animation) {clearAnimation();mLoadAngleAnim.start();mMovePointAnim.start();}@Overridepublic void onAnimationRepeat(Animation animation) {}});animator1.setDuration(mExpandAnimDuration);animator1.setInterpolator(new LinearInterpolator());mTranslateAnim = animator1;
onDraw中繪制代碼
if (mStatus == Status.EXPAND) {float left = (mWidth - mCurrLength) / 2f;float right = (mWidth + mCurrLength) / 2f;float r = mHeight / 2f;canvas.drawRoundRect(new RectF(left, 0, right, mHeight), r, r, mBgPaint);canvas.save();mTextPaint.setStyle(Paint.Style.FILL);canvas.translate(mTranslationX, 0);//大圓的圓心 半徑float cX = mWidth / 2f;float cY = mHeight / 2f;float radius = mHeight / 2 / 3f;canvas.drawCircle(cX, cY, radius, mTextPaint);//上方小圓的參數(shù)float rr = radius / 2f;float cYY = mHeight / 2 - (radius + rr / 3);canvas.drawCircle(cX, cYY, rr, mTextPaint);//左下小圓參數(shù)float cXX = (float) (cX - Math.sqrt(2) / 2f * (radius + rr / 3f));cYY = (float) (mHeight / 2 + Math.sqrt(2) / 2f * (radius + rr / 3f));canvas.drawCircle(cXX, cYY, rr, mTextPaint);//右下小圓參數(shù)cXX = (float) (cX + Math.sqrt(2) / 2f * (radius + rr / 3f));canvas.drawCircle(cXX, cYY, rr, mTextPaint);canvas.restore();}
加載動(dòng)畫
加載動(dòng)畫分三部分,右側(cè)的旋轉(zhuǎn)動(dòng)畫,正弦軌跡運(yùn)動(dòng)的小球動(dòng)畫,進(jìn)度更新的動(dòng)畫。正弦動(dòng)畫要求出正弦函數(shù)的周期,y軸偏移量,x軸偏移量。
ValueAnimator animator2 = ValueAnimator.ofFloat(0, 1);animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {mLoadAngle += mLoadRotateAnimSpeed;invalidate();}});animator2.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {mStatus = Status.LOAD;}@Overridepublic void onAnimationEnd(Animator animation) {mLoadAngleAnim.cancel();}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});animator2.setDuration(Integer.MAX_VALUE);animator2.setInterpolator(new LinearInterpolator());mLoadAngleAnim = animator2;
onDraw中繪制代碼:
if (mStatus == Status.LOAD || mStatus == Status.END) {float left = (mWidth - mCurrLength) / 2f;float right = (mWidth + mCurrLength) / 2f;float r = mHeight / 2f;mBgPaint.setColor(mProgressColor);canvas.drawRoundRect(new RectF(left, 0, right, mHeight), r, r, mBgPaint);if (mProgress != 100) {for (int i = 0; i < mFourMovePoints.length; i++) {if (mFourMovePoints[i].isDraw)canvas.drawCircle(mFourMovePoints[i].moveX, mFourMovePoints[i].moveY, mFourMovePoints[i].radius, mTextPaint);}}float progressRight = mProgress * mWidth / 100f;mBgPaint.setColor(mBgColor);canvas.save();canvas.clipRect(0, 0, progressRight, mHeight);canvas.drawRoundRect(new RectF(left, 0, right, mHeight), r, r, mBgPaint);canvas.restore();if (mProgress != 100) {canvas.drawCircle(mWidth - mHeight / 2, mHeight / 2, mHeight / 2, mBgPaint);canvas.save();mTextPaint.setStyle(Paint.Style.FILL);canvas.rotate(mLoadAngle, mWidth - mHeight / 2, mHeight / 2);canvas.drawCircle(mWidth - mHeight + 30, getCenterY(mWidth - mHeight + 30, 5), 5, mTextPaint);canvas.drawCircle(mWidth - mHeight + 45, getCenterY(mWidth - mHeight + 45, 8), 8, mTextPaint);canvas.drawCircle(mWidth - mHeight + 68, getCenterY(mWidth - mHeight + 68, 11), 11, mTextPaint);canvas.drawCircle(mWidth - mHeight + 98, getCenterY(mWidth - mHeight + 98, 14), 14, mTextPaint);canvas.restore();}Paint.FontMetrics fm = mTextPaint.getFontMetrics();float y = mHeight / 2 + (fm.descent - fm.ascent) / 2 - fm.descent;canvas.drawText(mProgress + "%", mWidth / 2, y, mTextPaint);}
源碼地址:
https://github.com/ietf626/360DownLoadView
到這里就結(jié)束啦。
評(píng)論
圖片
表情
