android实现下载功能实现,Android仿360市场下载按钮的实现方法

首先来看看效果图:

8d153fda4e0f39901e9938db1a2097bc.gif

无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述view的状态。

public enum Status { NORMAL, START, PRE, EXPAND, LOAD, END }

收缩动画

使用动画不断改变圆角矩形的宽度,触发重绘。代码如下:

private void initAnim() {

Animation animation1 = new Animation() {

@Override

protected 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() {

@Override

public void onAnimationStart(Animation animation) {

mStatus = Status.START;

}

@Override

public void onAnimationEnd(Animation animation) {

}

@Override

public 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);

}

}

准备动画

此时旋转动画,是通过canvas绘制背景圆和三个小圆,然后不断旋转画布来实现的,具体求圆心坐标和角度动画我们直接看代码:

ValueAnimator animator = ValueAnimator.ofFloat(0, 1);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mAngle += mPreAnimSpeed;

invalidate();

}

});

animator.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

mStatus = Status.PRE;

}

@Override

public void onAnimationEnd(Animator animation) {

mAngleAnim.cancel();

startAnimation(mTranslateAnim);

}

@Override

public void onAnimationCancel(Animator animation) {

}

@Override

public 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);

//上方小圆的参数

float rr = radius / 2f;

float cYY = mHeight / 2 - (radius + rr / 3);

canvas.drawCircle(cX, cYY, rr, mTextPaint);

//左下小圆参数

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);

//右下小圆参数

cXX = (float) (cX + Math.sqrt(2) / 2f * (radius + rr / 3f));

canvas.drawCircle(cXX, cYY, rr, mTextPaint);

canvas.restore();

}

展开动画

展开动画也是不断改变view的宽度并重绘圆角矩形,同时需要对准备动画的状态进行向右位移。

Animation animator1 = new Animation() {

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

mCurrLength = mHeight + (mWidth - mHeight) * interpolatedTime;

mTranslationX = (mWidth - mHeight) / 2 * interpolatedTime;

invalidate();

}

};

animator1.setAnimationListener(new Animation.AnimationListener() {

@Override

public void onAnimationStart(Animation animation) {

mStatus = Status.EXPAND;

}

@Override

public void onAnimationEnd(Animation animation) {

clearAnimation();

mLoadAngleAnim.start();

mMovePointAnim.start();

}

@Override

public 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);

//上方小圆的参数

float rr = radius / 2f;

float cYY = mHeight / 2 - (radius + rr / 3);

canvas.drawCircle(cX, cYY, rr, mTextPaint);

//左下小圆参数

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);

//右下小圆参数

cXX = (float) (cX + Math.sqrt(2) / 2f * (radius + rr / 3f));

canvas.drawCircle(cXX, cYY, rr, mTextPaint);

canvas.restore();

}

加载动画

加载动画分三部分,右侧的旋转动画,正弦轨迹运动的小球动画,进度更新的动画。正弦动画要求出正弦函数的周期,y轴偏移量,x轴偏移量。

ValueAnimator animator2 = ValueAnimator.ofFloat(0, 1);

animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mLoadAngle += mLoadRotateAnimSpeed;

invalidate();

}

});

animator2.addListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation) {

mStatus = Status.LOAD;

}

@Override

public void onAnimationEnd(Animator animation) {

mLoadAngleAnim.cancel();

}

@Override

public void onAnimationCancel(Animator animation) {

}

@Override

public 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);

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值