Android仿360市场下载按钮
龙旋
共 9390字,需浏览 19分钟
· 2022-02-15
先看一下效果:
无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述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);
}
源码地址:
https://github.com/ietf626/360DownLoadView
到这里就结束啦。
评论
Pura品牌焕新,华为高端市场“失去的都要拿回来”
Pura 70系列,注定会成为华为手机的另一个“转折点”。作 者 丨 宿艺编 辑 丨 子淇手机新旗舰,果然还是看华为。从4月15日到18日的三天时间中,华为Pura 70系列不断刷爆各大社交平台和媒体报道,并一举推动了中国手机市场的三个改变
壹观察
23
十万亿智慧养老市场,走到哪一步了?
《2024年智慧康养平台模式发展研究报告》即将发布。文|王菲当前,中国人口老龄化程度不断加剧,为了应对日益凸显的养老难题,构建多层次养老服务体系成为社会关注的热点。根据最新发布的《中华人民共和国2023年国民经济和社会发展统计公报》显示,我国60岁及以上的老年人口数量已达到2.97亿,占全国总人口的
亿欧网
0
百问商业航天④|百亿农业遥感市场,机会在何方?
泰伯网【百问商业航天】是国内首档商业航天问答短视频栏目,拆解百个商业航天热议话题,汇聚百位产业创新者智识,以PUGC+AIGC铸造商业航天「创新者百科」。记录中国商业航天走向大时代的铿锵足音,为产业发展争取更大的话语权和影响力。本期问题:百亿农业遥感市场,机会在何方?揭榜嘉宾:戴维序 &n
泰伯网
0
超赞!这个ChatGPT提问教程,PDF免费下载
你好,我是郭震AI来袭,我们该如何学习?今天先分享给大家一份超好的GPT提问指南。教程的详细介绍参考下面视频:这个PDF资料旨在教我们更好的给GPT发送指令,让GPT更准确的回答我们的提问。一共有30页,内容包括7个小章节,按照逻辑展开。分别介绍文本回答,代码辅助,结构化结果输出,非结构化结构输出,
Python与算法社区
3
下沉市场对黄金的偏爱,停滞在金价飙升之前
狂买还是狂卖?冲击万店,汉堡界能跑出下一个蜜雪冰城吗?最近一段时间金价的暴涨,已从部分人的惊喜变成大众的惊吓。大众的讨论从升值贬值、这个时间段入手是否合适,开始变成“上次金价暴涨世界发生了什么?”的担忧。金价狂涨在互联网中已经演变为大众话题,无论准不准备囤黄金,手头有没有黄金,都或多或少关注着金价的
亿欧网
0
中国服务器操作系统行业市场研究报告
本文来源于“沙利文:2023年中国服务器操作系统行业市场研究报告”。得益于新基建快速推进、政策引导下信创产业的蓬勃发展,国产服务器操作系统正逐步崛起。中国基础软件根技术自主掌控能力重视程度不断提高,越来越多的中国企业已经意识到其重要性,正在以更加积极拥抱的态度面对服务器操作系统领域的国产化替代趋势。
架构师技术联盟
1806
图解操作系统、网络、计算机组成PDF下载!
我去年去面试的时候发现字节跳动、腾讯这类大厂非常非常重视计算机基础,像计算机网络、操作系统都是它们的重点。我当时因为计算机基础知识准备的还可以才拿到了这些大厂的 Offer!今天就给大家分享一下我之前面试经常看的一些关于计算机基础的 PDF 资料!图解计算机系统《图解系统》主要是操作系统的内容比较多
java1234
0
超给力,从计算机基础到云原生容器化,83 张全领域高清思维导图免费下载!
今天给大家推荐一个开源项目是「learning_mind_map」,【思维导图】盒子,涉及的方向有 C/C++,Golang,Linux,云原生,数据库,DPDK,音视频开发,TCP/IP,数据结构,计算机原理等等。每个方向底下还有很多细分的子方向,每个子方向包含一张或几张思维导图,共 81 张,帮
开源Linux
10