当前位置: 代码迷 >> Android >> Android中使用自定义View实现下载进度的展示
  详细解决方案

Android中使用自定义View实现下载进度的展示

热度:92   发布时间:2016-04-27 22:40:58.0
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 <?xml version="1.0" encoding="utf-8"?> 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 xmlns:android="http://schemas.android.com/apk/res/android" 2     xmlns:custom="http://schemas.android.com/apk/res-auto" 3     xmlns:tools="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

  相关解决方案