欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿360市场下载按钮的实现方法

程序员文章站 2023-11-24 12:14:28
首先来看看效果图: 无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述view的状态...

首先来看看效果图:

Android仿360市场下载按钮的实现方法

无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述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://xiazai.jb51.net/201705/yuanma/metal626-360downloadview(jb51.net).rar

总结

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