一般有下载功能的应用都会有这样一个场景,需要一个图标来标识不同的状态。之前在公司的项目中写过一个,今天抽空来整理一下。
一般下载都会有这么几种状态:未开始、等待、正在下载、下载结束,当然有时候会有下载出错的状态。等待状态是指用户点击开始下载,但是线程池中没有空闲的线程来处理该次下载,所以状态为等待。
效果图:
这里我只是演示了一下下载和暂停的状态,其他状态没有演示,在代码中设置就可以了。
实现代码:
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 @Override
104 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 绘制下载中的view
129 @param canvas
130 /
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 //计算文字垂直居中的baseline
147 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 绘制暂停时的view
155 @param canvas
156 /
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 progress
177 /
178 public void setProgress(int progress) {
179 mProgress = progress;
180 postInvalidate();
181 }
182
183 /
184 设置下载状态
185 @param status
186 */
187 public void setStatus(int status) {
188 this.mStatus = status;
189 postInvalidate();
190 }
191
192 /
193 获取下载状态
194 @return
195 */
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.DownloadPercentView
11 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 @Override
21 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 @Override
27 public void onClick(View v) {
28 if(mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PEDDING
29 || mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PAUSED) {
30 downloading = true;
31 mDownloadPercentView.setStatus(DownloadPercentView.STATUS_DOWNLOADING);
32 //模拟下载
33 new Thread(new Runnable() {
34 @Override
35 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 @Override
61 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 }