Android自定义View叶子旋转完整版(六)
上一篇实现多叶子飘动旋转,今天完成最后的功能。
1、添加右侧旋转枫叶
2、添加滑动条效果,显示百分比
3、修复叶子飘出边框问题
1、添加右侧旋转叶子
bitmap turnbitmap = ((bitmapdrawable) mresources.getdrawable(r.drawable.fengshan, null)).getbitmap(); int turnleafangle = 0; private void setturnleaf(canvas canvas) { matrix matrix = new matrix(); turnleafangle = turnleafangle + 3; matrix.posttranslate((width - rightcirclewidth/2 - turnbitmap.getwidth()/2), (height - rightcirclewidth/2 - turnbitmap.getheight()/2)); matrix.postrotate(turnleafangle, width - rightcirclewidth/2 - turnbitmap.getwidth()/2 + turnbitmap.getwidth()/2, height - rightcirclewidth/2 - turnbitmap.getheight()/2 + turnbitmap.getheight()/2); canvas.drawbitmap(turnbitmap, matrix, new paint()); }
代码很明确,首先通过matrix.posttranslate(float dx, float dy)把turnbitmap定位到最右侧圆圈
再通过matrix.postrotate(float degress, float dx, float dy);设置旋转角度,每次角度+3°
其中degress为旋转角度,(dx,dy)为旋转中心点坐标
2、添加滑动效果
原理就是覆盖一层不同颜色的图层。根据当前百分比,分别画一个半圆,画一个正方形
a、定义一个圆形rectf(为什么不是半圆?因为画圆弧的其实角度从水平线右侧开始)
progressarcrectf = new rectf(0, 0, height, height);
b、定义一个长方形rectf,长方形x坐标起点即时圆形半径
progressrectf = new rectf(height/2, 0, width, height);
c、画出圆弧canvas.drawarc(rectf rectf, float startangle, float sweepangle, boolean usecenter, paint paint)
startangle:起始角度,默认从右侧水平线开始
sweepangle:为旋转的角度,顺时针旋转
usecenter:true只画出弧线,false则画出圆心到弧线的区域
//画滑动后的背景条 int currentprogresswidht = currentprogress * (width - borderwidth)/100; if(currentprogresswidht < leftcirclewidth/2) { //angle取值范围0~90 int angle = 90 * currentprogresswidht / (leftcirclewidth/2); // 起始的位置 int startangle = 180 - angle; // 扫过的角度 int sweepangle = 2 * angle; canvas.drawarc(progressarcrectf, startangle, sweepangle, false, progressbgpaint); }else { //画左边半圆形滑过部分 canvas.drawarc(progressarcrectf, 90, 180, false, progressbgpaint); progressrectf.left = borderwidth + leftcirclewidth/2; progressrectf.right = borderwidth + currentprogresswidht; //画中间滑过部分 canvas.drawrect(progressrectf, progressbgpaint); }
给leafview.java添加一个
public void setcurrentprogress(int currentprogress) { this.currentprogress = currentprogress; }
3、修复叶子飘动范围
这个简单,就是设置叶子的rect坐标起点+边框距离
赋上所有代码
1、activity_leaf.xml
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content_leaf" android:layout_width="match_parent" android:layout_height="match_parent"> <relativelayout android:layout_width="226dp" android:layout_height="45dp"> <com.zjcpo.t170313_countdowntimer.leafview android:id="@+id/leafview" android:layout_width="226dp" android:layout_height="45dp" android:layout_centerhorizontal="true" /> </relativelayout> </relativelayout>
2、leafview.java
import android.content.context; import android.content.res.resources; import android.graphics.bitmap; import android.graphics.canvas; import android.graphics.color; import android.graphics.matrix; import android.graphics.paint; import android.graphics.rect; import android.graphics.rectf; import android.graphics.drawable.bitmapdrawable; import android.util.attributeset; import android.util.log; import android.view.view; import java.util.linkedlist; import java.util.list; import java.util.random; import java.util.jar.attributes; /** * created by jiemiao.zhang on 2017-3-15. */ public class leafview extends view { private string tag = "--------leafview"; private resources mresources; //背景图、叶子 private bitmap mleafbitmap, bgbitmap, turnbitmap; //整个控件的宽度和高度 private int width, height; //最外层边框宽度 private int borderwidth; //右侧圆形直径 private int rightcirclewidth; //左侧圆形直径 private int leftcirclewidth; private paint bgpaint; private rectf bgrect; private rect bgdestrect; //进度条实时背景 private paint progressbgpaint; //进度条左侧半圆,进度条中间长方形部分rect private rectf progressarcrectf, progressrectf; //当前百分比0~100 private int currentprogress = 0; //存放叶子lsit private list<leaf> leaflist; //叶子的宽和高 private int mleafwidth, mleafheight; //叶子滑动一周的时间5秒 private final static long cycletime = 5000; //叶子数量 private final static int leafnumber = 6; public leafview(context context, attributeset attrs) { super(context, attrs); mresources = getresources(); mleafbitmap = ((bitmapdrawable) mresources.getdrawable(r.drawable.leaf, null)).getbitmap(); mleafwidth = mleafbitmap.getwidth(); mleafheight = mleafbitmap.getheight(); turnbitmap = ((bitmapdrawable) mresources.getdrawable(r.drawable.fengshan, null)).getbitmap(); bgbitmap = ((bitmapdrawable) mresources.getdrawable(r.drawable.leaf_kuang, null)).getbitmap(); bgpaint = new paint(); bgpaint.setcolor(mresources.getcolor(r.color.bg_color)); //进度条实时背景 progressbgpaint = new paint(); progressbgpaint.setcolor(mresources.getcolor(r.color.progress_bg_color)); //获取所有叶子的信息,放入list leaflist = getleafs(leafnumber); } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); width = w; height = h; borderwidth = height * 10/64; rightcirclewidth = width * 62/303; leftcirclewidth = height - 2 * borderwidth; bgdestrect = new rect(0, 0 , width, height); bgrect = new rectf(0, 0 , width, height); progressarcrectf = new rectf(borderwidth, borderwidth, height - borderwidth, height - borderwidth); progressrectf = new rectf(borderwidth+(height-2*borderwidth)/2, borderwidth, width-rightcirclewidth/2, height-borderwidth); log.i("leftmarginwidth", (borderwidth + leftcirclewidth/2) + ""); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); //画背景颜色到画布 canvas.drawrect(bgrect, bgpaint); if(currentprogress <= 100) { //画叶子 int size = leaflist.size(); for (int i=0; i<size; i++) { leaf leaf = leaflist.get(i); //获取叶子坐标 getlocation(leaf); //获取叶子旋转角度 getrotate(leaf); canvas.save(); matrix matrix = new matrix(); //设置滑动 matrix.posttranslate(leaf.x, leaf.y); //设置旋转 matrix.postrotate(leaf.rotateangle, leaf.x + mleafwidth / 2, leaf.y + mleafheight / 2); //添加叶子到画布 canvas.drawbitmap(mleafbitmap, matrix, new paint()); canvas.restore(); //画滑动后的背景条 int currentprogresswidht = currentprogress * (width - borderwidth - rightcirclewidth/2)/100; if(currentprogresswidht < leftcirclewidth/2) { //angle取值范围0~90 int angle = 90 * currentprogresswidht / (leftcirclewidth/2); log.i(tag, "angle :" + angle); // 起始的位置 int startangle = 180 - angle; // 扫过的角度 int sweepangle = 2 * angle; canvas.drawarc(progressarcrectf, startangle, sweepangle, false, progressbgpaint); }else { //画左边半圆形滑过部分 canvas.drawarc(progressarcrectf, 90, 180, false, progressbgpaint); progressrectf.left = borderwidth + leftcirclewidth/2; progressrectf.right = borderwidth + currentprogresswidht; //画中间滑过部分 canvas.drawrect(progressrectf, progressbgpaint); } } //调用ondraw()重复滑动 if(currentprogress < 100) { postinvalidate(); } } //画背景图片到画布 canvas.drawbitmap(bgbitmap, null, bgdestrect, null); //画右边选择风叶 setturnleaf(canvas); //画百分比 settext(canvas); } int turnleafangle = 0; private void setturnleaf(canvas canvas) { matrix matrix = new matrix(); turnleafangle = turnleafangle + 3; matrix.posttranslate((width - rightcirclewidth/2 - turnbitmap.getwidth()/2), (height - rightcirclewidth/2 - turnbitmap.getheight()/2)); matrix.postrotate(turnleafangle, width - rightcirclewidth/2 - turnbitmap.getwidth()/2 + turnbitmap.getwidth()/2, height - rightcirclewidth/2 - turnbitmap.getheight()/2 + turnbitmap.getheight()/2); canvas.drawbitmap(turnbitmap, matrix, new paint()); } //显示百分比数字,大于3%开始显示,到50%停止滑动 private void settext(canvas canvas) { paint painttext = new paint(); painttext.setcolor(color.white); painttext.settextsize(30); int textx = currentprogress * width / 100; textx = currentprogress < 50 ? (currentprogress * width / 100) : (width/2); if(currentprogress > 3) { canvas.drawtext(currentprogress + "%", textx, height/2 + 10,painttext); } } //获取每片叶子在xy轴上的滑动值 private void getlocation(leaf leaf) { float betweentime = leaf.starttime - system.currenttimemillis(); //周期结束再加一个cycletime if(betweentime < 0) { leaf.starttime = system.currenttimemillis() + cycletime + new random().nextint((int) (cycletime)); betweentime = cycletime; } //通过时间差计算出叶子的坐标 float fraction = (float) betweentime / cycletime; float x = (int)(width * fraction); //防止叶子飘出边框 leaf.x = x < borderwidth ? borderwidth : x; float w = (float) ((float) 2 * math.pi / width); int y = (int) (18 * math.sin(w * x)) + (height-mleafheight)/2; //防止叶子飘出边框 y = y > (height - borderwidth) ? (height - borderwidth) : y; y = y < borderwidth ? borderwidth : y; leaf.y = y; } //获取每片叶子的旋转角度 private void getrotate(leaf leaf) { float scale = ((leaf.starttime - system.currenttimemillis())%cycletime)/ (float)cycletime; int rotate = (int)(scale * 360); leaf.rotateangle = rotate; } private class leaf { // 叶子的坐标 float x, y; // 旋转角度 int rotateangle; // 起始时间(ms) long starttime; } private list<leaf> getleafs(int leafsize) { list<leaf> list = new linkedlist<leaf>(); for (int i=0; i<leafsize; i++) { list.add(getleaf()); } return list; } //使叶子初始时间有间隔 int addtime; private leaf getleaf() { random random = new random(); leaf leaf = new leaf(); leaf.rotateangle = random.nextint(360); addtime += random.nextint((int) (cycletime)); leaf.starttime = system.currenttimemillis() + cycletime + addtime; return leaf; } public void setcurrentprogress(int currentprogress) { this.currentprogress = currentprogress; } } 3、leafactivity.java public class leafactivity extends activity { private leafview leafview; private int mprogress = 0; handler mhandler = new handler() { public void handlemessage(message msg) { if (mprogress < 40) { mprogress += 1; // 随机800ms以内刷新一次 mhandler.sendemptymessagedelayed(1, new random().nextint(800)); leafview.setcurrentprogress(mprogress); } else { mprogress += 1; // 随机1200ms以内刷新一次 mhandler.sendemptymessagedelayed(1, new random().nextint(100)); leafview.setcurrentprogress(mprogress); } }; }; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_leaf); leafview = (leafview) findviewbyid(r.id.leafview); mhandler.sendemptymessagedelayed(1, 3000); } }
最后再看下效果
总结
看过前5篇的很好理解,用到的技术点之前都讲到了。这篇主要就是几个百分比函数的计算。
比如设置半圆时弧度如何计算,圆弧对应的百分比,滑动区域长方形的起点坐标计算,去掉边框后的坐标计算
画半圆必须要有一个完整圆形rect,因为drawarc()从右侧半径水平起始角度,顺时针。然功能要求我们从左侧圆形开始画,所以要通过一个算法,假如当前百分比为4%,需要画30°的圆弧,那么起始角度为165°=180°-15°,画出角度30%
通过matrix.postrotate()实现旋转功能时,必须加上当前view的坐标及二分之一长宽
需要图片等信息的可以从下面的github地址下载,不过原文比较复杂
参考 https://github.com/ajian-studio/galeafloading
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。