首先来看看效果图:
无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述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);
}
项目主页:http://www.open-open.com/lib/view/home/1494985743108
本地下载:http://xiazai./201705/yuanma/Metal626-360DownLoadView().rar
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# android
# 按钮样式
# 开关按钮
# 圆角按钮
# Android按钮按下的时候改变颜色实现方法
# Android编程实现设置按钮背景透明与半透明及图片背景透明的方法
# 如何在Android中实现渐显按钮的左右滑动效果
# Android实现圆角Button按钮
# Android单选按钮对话框用法实例分析
# Android动画 实现开关按钮动画(属性动画之平移动画)实例代码
# Android自定义实现开关按钮代码
# Android利用悬浮按钮实现翻页效果
# Android学习系列一用按钮实现显示时间
# 安卓(android)仿电商app商品详情页按钮浮动效果
# 小圆
# 加载
# 来实现
# 都是
# 圆角
# 几个
# 偏移量
# 本地下载
# 来看看
# 要对
# 这篇文章
# 谢谢大家
# 时需
# 有疑问
# AnimationListener
# setAnimationListener
# LinearInterpolator
# onAnimationStart
# onAnimationEnd
# mStatus
相关文章:
如何在云指建站中生成FTP站点?
如何高效搭建专业期货交易平台网站?
如何在万网主机上快速搭建网站?
如何通过万网虚拟主机快速搭建网站?
如何在Tomcat中配置并部署网站项目?
如何在景安云服务器上绑定域名并配置虚拟主机?
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
宝塔Windows建站如何避免显示默认IIS页面?
头像制作网站在线制作软件,dw网页背景图像怎么设置?
如何在万网ECS上快速搭建专属网站?
网站制作说明怎么写,简述网页设计的流程并说明原因?
如何规划企业建站流程的关键步骤?
制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?
家庭服务器如何搭建个人网站?
学校建站服务器如何选型才能满足性能需求?
ui设计制作网站有哪些,手机UI设计网址吗?
长沙企业网站制作哪家好,长沙水业集团官方网站?
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
网站专业制作公司有哪些,做一个公司网站要多少钱?
存储型VPS适合搭建中小型网站吗?
建站主机服务器选购指南:轻量应用与VPS配置解析
如何选择美橙互联多站合一建站方案?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
陕西网站制作公司有哪些,陕西凌云电器有限公司官网?
建站主机如何安装配置?新手必看操作指南
专业商城网站制作公司有哪些,pi商城官网是哪个?
广州商城建站系统开发成本与周期如何控制?
建站之星后台管理如何实现高效配置?
如何做网站制作流程,*游戏网站怎么搭建?
上海网站制作开发公司,上海买房比较好的网站有哪些?
建站主机选购指南:核心配置与性价比推荐解析
网站网页制作专业公司,怎样制作自己的网页?
南平网站制作公司,2025年南平市事业单位报名时间?
如何在IIS服务器上快速部署高效网站?
c# await 一个已经完成的Task会发生什么
建站之星后台密码遗忘?如何快速找回?
学校为何禁止电信移动建设网站?
企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?
南宁网站建设制作定制,南宁网站建设可以定制吗?
Android自定义listview布局实现上拉加载下拉刷新功能
电商平台网站制作流程,电商网站如何制作?
建站之星后台密码如何安全设置与找回?
建站之星后台密码遗忘如何找回?
如何在建站之星网店版论坛获取技术支持?
如何获取免费开源的自助建站系统源码?
孙琪峥织梦建站教程如何优化数据库安全?
购物网站制作公司有哪些,哪个购物网站比较好?
香港服务器WordPress建站指南:SEO优化与高效部署策略
专业公司网站制作公司,用什么语言做企业网站比较好?
*请认真填写需求信息,我们会在24小时内与您取得联系。