你的位置:首页 > 操作系统

[操作系统]Android中使用自定义View实现下载进度的显示


  一般有下载功能的应用都会有这样一个场景,需要一个图标来标识不同的状态。之前在公司的项目中写过一个,今天抽空来整理一下。

  一般下载都会有这么几种状态:未开始、等待、正在下载、下载结束,当然有时候会有下载出错的状态。等待状态是指用户点击开始下载,但是线程池中没有空闲的线程来处理该次下载,所以状态为等待。

效果图:

 

 

  这里我只是演示了一下下载和暂停的状态,其他状态没有演示,在代码中设置就可以了。

实现代码:

1、自定义View

 1 public class DownloadPercentView extends View { 2  3   public final static int STATUS_PEDDING = 1; 4   public final static int STATUS_WAITING = 2; 5   public final static int STATUS_DOWNLOADING = 3; 6   public final static int STATUS_PAUSED = 4; 7   public final static int STATUS_FINISHED = 5; 8  9   // 画实心圆的画笔 10   private Paint mCirclePaint; 11   // 画圆环的画笔 12   private Paint mRingPaint; 13   // 绘制进度文字的画笔 14   private Paint mTxtPaint; 15   // 圆形颜色 16   private int mCircleColor; 17   // 圆环颜色 18   private int mRingColor; 19   // 半径 20   private int mRadius; 21   // 圆环宽度 22   private int mStrokeWidth = 2; 23   // 圆心x坐标 24   private int mXCenter; 25   // 圆心y坐标 26   private int mYCenter; 27   // 总进度 28   private int mTotalProgress = 100; 29   // 当前进度 30   private int mProgress; 31   //下载状态 32   private int mStatus = 1; 33  34   //默认显示的图片 35   private Bitmap mNotBeginImg; 36   //暂停时中间显示的图片 37   private Bitmap mPausedImg; 38   //等待时显示的图片 39   private Bitmap mWatiImg; 40   //下载完成时显示的图片 41   private Bitmap finishedImg; 42  43  44  45   public DownloadPercentView(Context context, AttributeSet attrs) { 46     super(context, attrs); 47     // 获取自定义的属性 48     initAttrs(context, attrs); 49     initVariable(); 50   } 51  52   private void initAttrs(Context context, AttributeSet attrs) { 53     TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, 54         R.styleable.DownloadPercentView, 0, 0); 55     mRadius = (int)typeArray.getDimension(R.styleable.DownloadPercentView_radius, 100); 56     mNotBeginImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_notBeginImg)).getBitmap(); 57     mPausedImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_pausedImg)).getBitmap(); 58     mWatiImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_waitImg)).getBitmap(); 59     finishedImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_finishedImg)).getBitmap(); 60  61     mNotBeginImg = big(mNotBeginImg, mRadius * 2, mRadius * 2); 62     mPausedImg = big(mPausedImg, mRadius * 2, mRadius * 2); 63     mWatiImg = big(mWatiImg, mRadius * 2, mRadius * 2); 64     finishedImg = big(finishedImg, mRadius * 2, mRadius * 2); 65  66     mStrokeWidth = (int)typeArray.getDimension(R.styleable.DownloadPercentView_strokeWidth, 2); 67  68 //    mRadius = Math.max(mNotBeginImg.getWidth()/2, mNotBeginImg.getHeight()/2) + mStrokeWidth; 69     mCircleColor = typeArray.getColor(R.styleable.DownloadPercentView_circleColor, 0xFFFFFFFF); 70     mRingColor = typeArray.getColor(R.styleable.DownloadPercentView_ringColor, 0xFFFFFFFF); 71   } 72  73   private void initVariable() { 74     //初始化绘制灰色圆的画笔 75     mCirclePaint = new Paint(); 76     mCirclePaint.setAntiAlias(true); 77     mCirclePaint.setColor(mCircleColor); 78     mCirclePaint.setStyle(Paint.Style.STROKE); 79     mCirclePaint.setStrokeWidth(mStrokeWidth); 80  81     //初始化绘制圆弧的画笔 82     mRingPaint = new Paint(); 83     mRingPaint.setAntiAlias(true); 84     mRingPaint.setColor(mRingColor); 85     mRingPaint.setStyle(Paint.Style.STROKE); 86     mRingPaint.setStrokeWidth(mStrokeWidth); 87  88     //初始化绘制文字的画笔 89     mTxtPaint = new Paint(); 90     mTxtPaint.setAntiAlias(true); 91     mTxtPaint.setColor(Color.parseColor("#52ce90")); 92     mTxtPaint.setTextAlign(Paint.Align.CENTER); 93     mTxtPaint.setTextSize(24); 94  95   } 96  97   @Override 98   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 99     int width = (int)Math.ceil(mRadius) * 2;100     setMeasuredDimension(width, width);101   }102   103   @Override104   protected void onDraw(Canvas canvas) {105     mXCenter = getWidth() / 2;106     mYCenter = getHeight() / 2;107     switch (mStatus) {108       case STATUS_PEDDING:109         canvas.drawBitmap(mNotBeginImg, 0, 0, null);110         break;111       case STATUS_WAITING:112         canvas.drawBitmap(mWatiImg, 0, 0, null);113         break;114       case STATUS_DOWNLOADING:115         drawDownloadingView(canvas);116         break;117       case STATUS_PAUSED:118         drawPausedView(canvas);119         break;120       case STATUS_FINISHED:121         canvas.drawBitmap(finishedImg, 0, 0, null);122         break;123     }124 125   }126 127   /**128    * 绘制下载中的view129    * @param canvas130   */131   private void drawDownloadingView(Canvas canvas) {132     //绘制灰色圆环133     canvas.drawCircle(mXCenter, mYCenter, mRadius - mStrokeWidth/2, mCirclePaint);134 135     //绘制进度扇形圆环136     RectF oval = new RectF();137     //设置椭圆上下左右的坐标138     oval.left = mXCenter - mRadius + mStrokeWidth/2;139     oval.top = mYCenter - mRadius + mStrokeWidth/2;140     oval.right = mXCenter + mRadius - mStrokeWidth/2;141     oval.bottom = mYCenter + mRadius - mStrokeWidth/2;142     canvas.drawArc(oval, -90, ((float)mProgress / mTotalProgress) * 360, false, mRingPaint);143 144     //绘制中间百分比文字145     String percentTxt = String.valueOf(mProgress);146     //计算文字垂直居中的baseline147     Paint.FontMetricsInt fontMetrics = mTxtPaint.getFontMetricsInt();148     float baseline = oval.top + (oval.bottom - oval.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;149     canvas.drawText(percentTxt, mXCenter, baseline, mTxtPaint);150 151   }152 153   /**154    * 绘制暂停时的view155    * @param canvas156   */157   private void drawPausedView(Canvas canvas) {158     //绘制灰色圆环159     canvas.drawCircle(mXCenter, mYCenter, mRadius - mStrokeWidth/2, mCirclePaint);160 161     //绘制进度扇形圆环162     RectF oval = new RectF();163     //设置椭圆上下左右的坐标164     oval.left = mXCenter - mRadius + mStrokeWidth/2;165     oval.top = mYCenter - mRadius + mStrokeWidth/2;166     oval.right = mXCenter + mRadius - mStrokeWidth/2;167     oval.bottom = mYCenter + mRadius - mStrokeWidth/2;168     canvas.drawArc(oval, -90, ((float) mProgress / mTotalProgress) * 360, false, mRingPaint);169 170     //绘制中间暂停图标171     canvas.drawBitmap(mPausedImg, 0, 0, null);172   }173 174   /**175    * 更新进度176    * @param progress177   */178   public void setProgress(int progress) {179     mProgress = progress;180     postInvalidate();181   }182 183   /**184    * 设置下载状态185    * @param status186   */187   public void setStatus(int status) {188     this.mStatus = status;189     postInvalidate();190   }191 192   /**193    * 获取下载状态194    * @return195   */196   public int getStatus() {197     return mStatus;198   }199 200   public static Bitmap big(Bitmap b,float x,float y)201   {202     int w=b.getWidth();203     int h=b.getHeight();204     float sx=(float)x/w;205     float sy=(float)y/h;206     Matrix matrix = new Matrix();207     matrix.postScale(sx, sy); // 长和宽放大缩小的比例208     Bitmap resizeBmp = Bitmap.createBitmap(b, 0, 0, w,209         h, matrix, true);210     return resizeBmp;211   }212 213 }

2、自定义属性

 1 <??> 2 <resources> 3  4   <declare-styleable name="DownloadPercentView"> 5     <attr name="radius" format="dimension"/> 6     <attr name="notBeginImg" format="string"/> 7     <attr name="waitImg" format="string"/> 8     <attr name="pausedImg" format="string"/> 9     <attr name="finishedImg" format="string"/>10     <attr name="strokeWidth" format="dimension"/>11     <attr name="circleColor" format="color"/>12     <attr name="ringColor" format="color"/>13   </declare-styleable>14   15 </resources>

3、使用自定义布局

  首先在布局文件中引用:

 1 <RelativeLayout ="http://schemas.android.com/apk/res/android" 2   ="http://schemas.android.com/apk/res-auto" 3   ="http://schemas.android.com/tools" 4   android:layout_width="match_parent" 5   android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" 6   android:paddingRight="@dimen/activity_horizontal_margin" 7   android:paddingTop="@dimen/activity_vertical_margin" 8   android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> 9 10   <com.bbk.lling.downloadpercentdemo.DownloadPercentView11     android:id="@+id/downloadView"12     android:layout_width="wrap_content"13     android:layout_height="wrap_content"14     android:layout_centerInParent="true"15     custom:notBeginImg="@drawable/ic_no_download"16     custom:waitImg="@drawable/ic_wait"17     custom:pausedImg="@drawable/ic_pause"18     custom:finishedImg="@drawable/ic_finished"19     custom:strokeWidth="2dp"20     custom:circleColor="#bdbdbd"21     custom:radius="18dp"22     custom:ringColor="#52ce90"/>23 24 </RelativeLayout>

 

  然后我这里在Activity使用一个线程来模拟下载过程来演示:

 1 package com.bbk.lling.downloadpercentdemo; 2  3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Handler; 6 import android.os.Message; 7 import android.view.View; 8  9 10 public class MainActivity extends Activity {11 12   public final static int MSG_UPDATE = 1;13   public final static int MSG_FINISHED = 2;14 15   private DownloadPercentView mDownloadPercentView;16   private int mDownloadProgress = 0;17   private Handler mHandler = new InnerHandler();18   private boolean downloading = false;19 20   @Override21   protected void onCreate(Bundle savedInstanceState) {22     super.onCreate(savedInstanceState);23     setContentView(R.layout.activity_main);24     mDownloadPercentView = (DownloadPercentView) findViewById(R.id.downloadView);25     mDownloadPercentView.setOnClickListener(new View.OnClickListener() {26       @Override27       public void onClick(View v) {28         if(mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PEDDING29             || mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PAUSED) {30           downloading = true;31           mDownloadPercentView.setStatus(DownloadPercentView.STATUS_DOWNLOADING);32           //模拟下载33           new Thread(new Runnable() {34             @Override35             public void run() {36               while (downloading) {37                 if(mDownloadProgress == 100) {38                   mHandler.sendEmptyMessage(MSG_FINISHED);39                   return;40                 }41                 mDownloadProgress += 1;42                 mHandler.sendEmptyMessage(MSG_UPDATE);43                 try{44                   Thread.sleep(100);45                 } catch (Exception e) {46                 }47 48               }49             }50           }).start();51         } else if(mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_DOWNLOADING){52           downloading = false;53           mDownloadPercentView.setStatus(DownloadPercentView.STATUS_PAUSED);54         }55       }56     });57   }58 59   class InnerHandler extends Handler {60     @Override61     public void handleMessage(Message msg) {62       switch (msg.what) {63         case MSG_FINISHED:64           mDownloadPercentView.setStatus(DownloadPercentView.STATUS_FINISHED);65           break;66         case MSG_UPDATE:67           mDownloadPercentView.setProgress(mDownloadProgress);68           break;69       }70       super.handleMessage(msg);71     }72   }73 74 75 }

 

源码下载:https://github.com/liuling07/DownloadPercentDemo