继承view实现下载进度条,大家可以参考修改出更好的实现方式,欢迎指正,下面是源码和截图:
1.测试代码:
DownloadProgressBar dpb; synchronized void updateUIData(float rate){ dpb.setProgress(rate); } void test(){ dpb=new DownloadProgressBar(this); dpb.setWH(100, 4); new Thread(new Runnable() { int rate = 0; @Override public void run() { while(true){ try { if(rate>100){ break; } myHandler.post(new Runnable() { //用handler在线程中刷新数据 @Override public void run() { Log.i(TAG,"####@@@@rate:"+rate); if(rate == 2){ rate+=2; }else if(rate ==10){ rate+=10; }else if(rate ==20){ rate+=10; }else if(rate ==50){ rate+=20; }else{ rate++; } updateUIData(rate); } }); Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); }
2.进度条源码
1>首先设置进度条的宽和高,代码里设定宽度应该为100的整数倍,不然进度条显示的数据并不准确。
2>文件下载的话,可以用上诉例子替换成不停的读以下载的文件大小,然后根据文件总大小得到相对比例,调用updateUIData(rate)刷新ui
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class DownloadProgressBar extends View{ private static final String TAG="DownloadProgressBar"; Context cxt; public DownloadProgressBar(Context context) { this(context, null); } public DownloadProgressBar(Context context, AttributeSet attrs) { super(context, attrs); cxt = context; this.setBackgroundResource(R.drawable.jdt02); bitmap =BitmapFactory.decodeResource(cxt.getResources(), R.drawable.jdt03); mCanvas = new Canvas(); mpaint = new Paint(); } private int w,h; /** * 设置进度条的宽高 * * @param w * 宽 * @param h * 高 * */ public void setWH(int w,int h){ this.w= w; this.h=h; } float rate ; float rate_t; /** * 设置进度比例 * * @param r * 当前占的比例值 * */ public void setProgress(float r){ this.rate_t = w/100*r; //(w/100)这里假定以w为100的整数倍 invalidate((int)rate,0,w,h); //invalidate(); } public void clearProgress(){ rate = 0; } Canvas mCanvas; Paint mpaint; Bitmap bitmap; //一个像素宽的绿色小图片 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); while(rate<=rate_t){ for(int i=0;i<w/100;i++){ Log.i(TAG,"rate:"+rate+",rate_t:"+rate_t); canvas.drawBitmap(bitmap, rate++, 0, null); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(w, h); } }
3.进度条改进版源码
前面代码出现的问题:
1.每次刷新因为只刷新部分区域,导致按键事件的时候,因为会重新刷新ui,而默认是invalidate()全刷新,导致前面部分的进度没有了
而如果用全部刷新来画每个像素的话,是非常消耗系统资源的,这里简单算下:
a>如果这里用的图片像素宽度是1px的话,而进度条的宽度为400,则
每次ondraw都从0开始画,drawCount = 1+2+3+4+...+400=(1+400)*400/2=80200;
import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; public class DownloadProgressBar extends View{ private static final String TAG="DownloadProgressBar"; Context cxt; public DownloadProgressBar(Context context) { this(context, null); } public DownloadProgressBar(Context context, AttributeSet attrs) { super(context, attrs); cxt = context; this.setBackgroundResource(R.drawable.bar_01); if(bitmap!=null){ bitmap.recycle(); } bitmap =BitmapFactory.decodeResource(cxt.getResources(), R.drawable.bar_04); //和背景大小一致的全绿色图片 mCanvas = new Canvas(); mpaint = new Paint(); } private int w,h; /** * 设置进度条的宽高 * * @param w * 宽 * @param h * 高 * */ public void setWH(int w,int h){ this.w= w; this.h=h; } float rate = 0; float rate_t; /** * 设置进度比例 * * @param r * 当前占的比例值 * */ public void setProgress(float r){ if(r>99){ this.setBackgroundResource(R.drawable.bar_04); return; } this.rate_t = w/100*r; //Log.i(TAG,"setProgress:rate="+rate+",rate_t:"+rate_t); //invalidate((int)rate,0,w,h); invalidate(); } public void clearProgress(){ rate = 0; } Canvas mCanvas; Paint mpaint; Bitmap bitmap; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // while(rate<=rate_t){ // for(int i=0;i<w/100;i++){ // //Log.i(TAG,"rate:"+rate+",rate_t:"+rate_t); // canvas.drawBitmap(bitmap, rate++, 0, null); // } // } clipDraw(canvas); } void clipDraw(Canvas canvas){ //用剪切区域来显示进度条,减少画单个像素的次数 canvas.save(); canvas.clipRect(0,0,rate_t, h); canvas.drawBitmap(bitmap,0, 0, null); canvas.restore(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(w, h); }