在网上看了些进度条效果,于是就想写关于这方面博客,先看下今天要实现一些进度条的效果图:
当然要实现这些效果是基于你对canvas类绘制一些图形是了解的,否则估计也不好看懂,我尽量讲的详细点,
先从简单的画圆开始一步步把这个效果实现出来,这样几乎每个人都能看的懂,
画圆的代码:
package com.example.pbdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/7/5. */ public class MyProgressView extends View { private Paint mPaint; public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setColor(Color.BLUE);//设置画笔的颜色 mPaint.setStrokeWidth(8);//设置画笔的宽度 mPaint.setAntiAlias(true);//设置看锯齿 mPaint.setStyle(Paint.Style.STROKE);//设置成空心 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100,100,80,mPaint); } }效果:
现在画个弧,示意图:
public class MyProgressView extends View { private Paint mPaint; public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setColor(Color.BLUE);//设置画笔的颜色 mPaint.setStrokeWidth(8);//设置画笔的宽度 mPaint.setAntiAlias(true);//设置看锯齿 mPaint.setStyle(Paint.Style.STROKE);//设置成空心 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100,100,80,mPaint); RectF rectF = new RectF(20,20,180,180); mPaint.setColor(Color.YELLOW); canvas.drawArc(rectF,0,30,false,mPaint); } }效果图:
ok,现在就差让弧度进行动态的改变,这样就达到黄色所表示的弧度是动态的,这就有个简单的计算,比如进度条最大值是100,刚开始是0,每过1秒后+1,同时去刷新界面,那么弧度怎么算呢,你看当进度条最大值为100时,刚好弧度走一圈,一圈是360度,假如当前进度为10,那么它所表示弧度=10/100*360,那么现在就可以写代码了,根据这个思路
package com.example.pbdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/7/5. */ public class MyProgressView extends View { private static final String TAG ="MyProgressView" ; private Paint mPaint;//这是画圆所用的画笔 private Paint anglePaint;//这是画弧的画笔 private int startingDegree = 0;//开始弧度 private int max = 100; private int progress; public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); anglePaint = new Paint(); anglePaint.setStrokeWidth(8); anglePaint.setColor(Color.YELLOW); mPaint.setColor(Color.BLUE);//设置画笔的颜色 mPaint.setStrokeWidth(8);//设置画笔的宽度 mPaint.setAntiAlias(true);//设置看锯齿 mPaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100,100,80,mPaint); RectF rectF = new RectF(20,20,180,180); canvas.drawArc(rectF,getStartingDegree(),getProgressAngle(),false,anglePaint); } /** * 弧度从哪角度开始 * @return */ public int getStartingDegree() { return startingDegree; } /** * 设置进度值,实时更新进度 * @param progress */ public void setProgress(int progress){ this.progress = progress; if (this.progress > max) { this.progress %= max; } invalidate(); } /** * 获取当前进度值 * @return */ public int getProgress(){ return progress; } /** * 弧度所经过的度 * @return */ private float getProgressAngle() { return getProgress() / (float) max * 360f; } }
要100毫秒去更新进度值
public class MainActivity extends AppCompatActivity { private Timer timer; private MyProgressView myprogressview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myprogressview = (MyProgressView) findViewById(R.id.myprogressview); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { myprogressview.setProgress(myprogressview.getProgress()+1); } }); } }, 1000, 100); } }效果:
现在添加一个需求就是在圆的中心点显示当前进度值,这个就要计算文字所在的坐标x,y了
分析图:
代码如下:
public class MyProgressView extends View { private static final String TAG ="MyProgressView" ; private Paint mPaint;//这是画圆所用的画笔 private Paint textPaint;//绘制文字的画笔 private Paint anglePaint;//这是画弧的画笔 private int startingDegree = 0;//开始弧度 private int max = 100; private int progress; public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); textPaint = new Paint(); textPaint.setColor(Color.RED); textPaint.setTextSize(24);//设置文字的大小 textPaint.setAntiAlias(true); mPaint = new Paint(); anglePaint = new Paint(); anglePaint.setStrokeWidth(8); anglePaint.setColor(Color.YELLOW); mPaint.setColor(Color.BLUE);//设置画笔的颜色 mPaint.setStrokeWidth(8);//设置画笔的宽度 mPaint.setAntiAlias(true);//设置看锯齿 mPaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(100,100,80,mPaint); RectF rectF = new RectF(20,20,180,180); float textHeight = textPaint.descent() + textPaint.ascent();//算出文字的高度 String text = getProgress()+"%"; canvas.drawText(text,20+80-textPaint.measureText(text)/2,20+80-textHeight/2,textPaint); canvas.drawArc(rectF,getStartingDegree(),getProgressAngle(),false,anglePaint); } /** * 弧度从哪角度开始 * @return */ public int getStartingDegree() { return startingDegree; } /** * 设置进度值,实时更新进度 * @param progress */ public void setProgress(int progress){ this.progress = progress; if (this.progress > max) { this.progress %= max; } invalidate(); } /** * 获取当前进度值 * @return */ public int getProgress(){ return progress; } /** * 弧度所经过的度 * @return */ private float getProgressAngle() { return getProgress() / (float) max * 360f; } }
MainActivity类中的代码不变,那么在这不贴出来了,现在看效果:
现在实现这个效果;
这里有一个值是定的,就是那个缺省的度数,比如是0.2*360,那么进度要跑的就是0.8*360,
代码如下:
package com.example.pbdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * Created by admin on 2016/7/5. */ public class MyProgressView extends View { private static final String TAG ="MyProgressView" ; private Paint textPaint;//绘制文字的画笔 private Paint anglePaint;//这是画弧的画笔 private int max = 100; private int progress; private float arcAngle = 360*0.8f;// public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPainters(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float startAngle = (float) (90+0.1*360f); float sweepAngle = progress / (float)max * arcAngle; canvas.drawArc(rectF,startAngle,sweepAngle,false,anglePaint); } /** * 设置进度值,实时更新进度 * @param progress */ public void setProgress(int progress){ this.progress = progress; if (this.progress > max) { this.progress %= max; } invalidate(); } /** * 获取当前进度值 * @return */ public int getProgress(){ return progress; } private void initPainters() { textPaint = new Paint(); textPaint.setColor(Color.RED); textPaint.setTextSize(24);//设置文字的大小 textPaint.setAntiAlias(true); anglePaint = new Paint(); anglePaint.setStrokeWidth(8); anglePaint.setColor(Color.parseColor("#D2691E")); anglePaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setAntiAlias(true); anglePaint.setStrokeCap(Paint.Cap.ROUND); } }每秒刷新一次,
myprogressview = (MyProgressView) findViewById(R.id.myprogressview); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { myprogressview.setProgress(myprogressview.getProgress()+1); } }); } }, 1000, 100);效果:
分析图:
现在只是实现了第一步,我们看着效果图是弧度是有二个颜色的,现在把弧度没扫过的颜色也绘制出来,这个其实很简单,底层是绘制一种颜色,上面是弧度经过的颜色
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float startAngle = (float) (90+0.1*360f); float sweepAngle = progress / (float)max * arcAngle; anglePaint.setColor(Color.parseColor("#D2691E")); canvas.drawArc(rectF, startAngle, arcAngle, false, anglePaint); anglePaint.setColor(Color.parseColor("#9ACD32")); canvas.drawArc(rectF,startAngle,sweepAngle,false,anglePaint); }效果:
现在进一步完善我们想要的效果,需要在圆的中心显示当前进度值,这个和上面讲的进度条中绘制文字是一样的,
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float startAngle = (float) (90+0.1*360f); float sweepAngle = progress / (float)max * arcAngle; anglePaint.setColor(Color.parseColor("#D2691E")); canvas.drawArc(rectF, startAngle, arcAngle, false, anglePaint); anglePaint.setColor(Color.parseColor("#9ACD32")); canvas.drawArc(rectF,startAngle,sweepAngle,false,anglePaint); float textHeight = textPaint.descent() + textPaint.ascent(); String text = progress+""; textPaint.setTextSize(50); canvas.drawText(text, 100+150-textPaint.measureText(text)/2, 100+150-textHeight/2, textPaint); textPaint.setTextSize(20); String suffixText = "%"; canvas.drawText(suffixText, 100+150+textPaint.measureText(text)/2+12,100+150+textHeight,textPaint); }效果:
现在就差绘制下面的文字了,
public class MyProgressView extends View { private static final String TAG ="MyProgressView" ; private Paint textPaint;//绘制文字的画笔 private Paint anglePaint;//这是画弧的画笔 private Paint bottomTextPaint; private int max = 100; private int progress; private float arcAngle = 360*0.8f;// public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPainters(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float startAngle = (float) (90+0.1*360f); float sweepAngle = progress / (float)max * arcAngle; anglePaint.setColor(Color.parseColor("#D2691E")); canvas.drawArc(rectF, startAngle, arcAngle, false, anglePaint); anglePaint.setColor(Color.parseColor("#9ACD32")); canvas.drawArc(rectF,startAngle,sweepAngle,false,anglePaint); float textHeight = textPaint.descent() + textPaint.ascent(); String text = progress+""; textPaint.setTextSize(50); canvas.drawText(text, 100+150-textPaint.measureText(text)/2, 100+150-textHeight/2, textPaint); textPaint.setTextSize(20); String suffixText = "%"; canvas.drawText(suffixText, 100+150+textPaint.measureText(text)/2+12,100+150+textHeight,textPaint); // String bottomText = "memory"; float arcBottomHeight = 150 * (float) (1 - Math.cos(36 / 180 * Math.PI));//文字的高度 canvas.drawText(bottomText,100+150-bottomTextPaint.measureText(bottomText)/2,400-arcBottomHeight,bottomTextPaint); } /** * 设置进度值,实时更新进度 * @param progress */ public void setProgress(int progress){ this.progress = progress; if (this.progress > max) { this.progress %= max; return; } invalidate(); } /** * 获取当前进度值 * @return */ public int getProgress(){ return progress; } private void initPainters() { bottomTextPaint = new Paint(); bottomTextPaint.setColor(Color.BLUE); bottomTextPaint.setTextSize(40); bottomTextPaint.setStrokeWidth(8); textPaint = new Paint(); textPaint.setColor(Color.RED); textPaint.setTextSize(24);//设置文字的大小 textPaint.setAntiAlias(true); anglePaint = new Paint(); anglePaint.setStrokeWidth(8); anglePaint.setColor(Color.parseColor("#D2691E")); anglePaint.setStyle(Paint.Style.STROKE);//设置成空心 anglePaint.setAntiAlias(true); anglePaint.setStrokeCap(Paint.Cap.ROUND); } }效果:
ok,第二个进度条效果算写完了,现在还差最后一个效果如下:
分析图:
代码;
package com.example.pbdemo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.view.WindowManager; /** * Created by admin on 2016/7/5. */ public class MyProgressView extends View { private static final String TAG ="MyProgressView" ; private Paint textPaint;//绘制文字的画笔 private Paint anglePaint;//这是画弧的画笔 private Paint reanglePaint ; private int max = 100; private int progress; public MyProgressView(Context context) { this(context,null); } public MyProgressView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); WindowManager wm = ((MainActivity)getContext()).getWindowManager(); initPainters(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float yHeight = getProgress()/(float)max*300; float angle = (float) (Math.acos((150 - yHeight) / 150) * 180 / Math.PI); float startAngle = 90 + angle;//起始弧度 float sweepAngle = 360 - angle * 2;//所经过的弧度 canvas.drawArc(rectF, startAngle, sweepAngle, false, anglePaint); canvas.save(); canvas.rotate(180, 250,250);//围绕rectF矩形所在的内切圆的圆心进行旋转 reanglePaint.setColor(Color.parseColor("#8DB6CD")); canvas.drawArc(rectF, 270 - angle, angle * 2, false, reanglePaint); canvas.restore(); } /** * 设置进度值,实时更新进度 * @param progress */ public void setProgress(int progress){ this.progress = progress; if (this.progress > max) { this.progress %= max; } invalidate(); } /** * 获取当前进度值 * @return */ public int getProgress(){ return progress; } private void initPainters() { textPaint = new Paint(); textPaint.setTextSize(36); textPaint.setAntiAlias(true); anglePaint = new Paint(); anglePaint.setStrokeWidth(8); anglePaint.setColor(Color.parseColor("#8B8386")); anglePaint.setAntiAlias(true); reanglePaint = new Paint(); reanglePaint.setAntiAlias(true); } }效果:
效果分析图:
现在就差一个显示进度条的值了,这个很简单,唯一要注意的是刚对canvas进行了旋转操作,这些操作是不可逆的,所以要恢复画布,不然绘制文字就倒了
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); RectF rectF = new RectF(100,100,400,400); float yHeight = getProgress()/(float)max*300; float angle = (float) (Math.acos((150 - yHeight) / 150) * 180 / Math.PI); float startAngle = 90 + angle;//起始弧度 float sweepAngle = 360 - angle * 2;//所经过的弧度 canvas.drawArc(rectF, startAngle, sweepAngle, false, anglePaint); canvas.save(); canvas.rotate(180, 250,250);//围绕rectF矩形所在的内切圆的圆心进行旋转 reanglePaint.setColor(Color.parseColor("#8DB6CD")); canvas.drawArc(rectF, 270 - angle, angle * 2, false, reanglePaint); canvas.restore(); String text = getProgress()+"%"; if (!TextUtils.isEmpty(text)) { float textHeight = textPaint.descent() + textPaint.ascent(); canvas.drawText(text, 100+150-textPaint.measureText(text)/2, 100+150-textHeight/2, textPaint); } }最终效果:
ok,今天任务完成了!