Android仿360市场下载按钮的实现方法
程序员文章站
2023-12-09 19:39:03
首先来看看效果图:
无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述view的状态...
首先来看看效果图:
无论多复杂的动画我们都是可以分割成小单元的,然后分步来实现。这个动画大概分为收缩,准备,加载,完成几个部分。为此定义一个枚举类来描述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
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。