Android中使用自定义View实现下载进度的显示
一般有下载功能的应用都会有这样一个场景,需要一个图标来标识不同的状态。之前在公司的项目中写过一个,今天抽空来整理一下。
一般下载都会有这么几种状态:未开始、等待、正在下载、下载结束,当然有时候会有下载出错的状态。等待状态是指用户点击开始下载,但是线程池中没有空闲的线程来处理该次下载,所以状态为等待。
效果图:
这里我只是演示了一下下载和暂停的状态,其他状态没有演示,在代码中设置就可以了。
实现代码:
1、自定义View
public class DownloadPercentView extends View { public final static int STATUS_PEDDING = 1;
public final static int STATUS_WAITING = 2;
public final static int STATUS_DOWNLOADING = 3;
public final static int STATUS_PAUSED = 4;
public final static int STATUS_FINISHED = 5; // 画实心圆的画笔
private Paint mCirclePaint;
// 画圆环的画笔
private Paint mRingPaint;
// 绘制进度文字的画笔
private Paint mTxtPaint;
// 圆形颜色
private int mCircleColor;
// 圆环颜色
private int mRingColor;
// 半径
private int mRadius;
// 圆环宽度
private int mStrokeWidth = 2;
// 圆心x坐标
private int mXCenter;
// 圆心y坐标
private int mYCenter;
// 总进度
private int mTotalProgress = 100;
// 当前进度
private int mProgress;
//下载状态
private int mStatus = 1; //默认显示的图片
private Bitmap mNotBeginImg;
//暂停时中间显示的图片
private Bitmap mPausedImg;
//等待时显示的图片
private Bitmap mWatiImg;
//下载完成时显示的图片
private Bitmap finishedImg; public DownloadPercentView(Context context, AttributeSet attrs) {
super(context, attrs);
// 获取自定义的属性
initAttrs(context, attrs);
initVariable();
} private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.DownloadPercentView, 0, 0);
mRadius = (int)typeArray.getDimension(R.styleable.DownloadPercentView_radius, 100);
mNotBeginImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_notBeginImg)).getBitmap();
mPausedImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_pausedImg)).getBitmap();
mWatiImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_waitImg)).getBitmap();
finishedImg = ((BitmapDrawable)typeArray.getDrawable(R.styleable.DownloadPercentView_finishedImg)).getBitmap(); mNotBeginImg = big(mNotBeginImg, mRadius * 2, mRadius * 2);
mPausedImg = big(mPausedImg, mRadius * 2, mRadius * 2);
mWatiImg = big(mWatiImg, mRadius * 2, mRadius * 2);
finishedImg = big(finishedImg, mRadius * 2, mRadius * 2); mStrokeWidth = (int)typeArray.getDimension(R.styleable.DownloadPercentView_strokeWidth, 2); // mRadius = Math.max(mNotBeginImg.getWidth()/2, mNotBeginImg.getHeight()/2) + mStrokeWidth;
mCircleColor = typeArray.getColor(R.styleable.DownloadPercentView_circleColor, 0xFFFFFFFF);
mRingColor = typeArray.getColor(R.styleable.DownloadPercentView_ringColor, 0xFFFFFFFF);
} private void initVariable() {
//初始化绘制灰色圆的画笔
mCirclePaint = new Paint();
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(mCircleColor);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setStrokeWidth(mStrokeWidth); //初始化绘制圆弧的画笔
mRingPaint = new Paint();
mRingPaint.setAntiAlias(true);
mRingPaint.setColor(mRingColor);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingPaint.setStrokeWidth(mStrokeWidth); //初始化绘制文字的画笔
mTxtPaint = new Paint();
mTxtPaint.setAntiAlias(true);
mTxtPaint.setColor(Color.parseColor("#52ce90"));
mTxtPaint.setTextAlign(Paint.Align.CENTER);
mTxtPaint.setTextSize(24); } @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = (int)Math.ceil(mRadius) * 2;
setMeasuredDimension(width, width);
} @Override
protected void onDraw(Canvas canvas) {
mXCenter = getWidth() / 2;
mYCenter = getHeight() / 2;
switch (mStatus) {
case STATUS_PEDDING:
canvas.drawBitmap(mNotBeginImg, 0, 0, null);
break;
case STATUS_WAITING:
canvas.drawBitmap(mWatiImg, 0, 0, null);
break;
case STATUS_DOWNLOADING:
drawDownloadingView(canvas);
break;
case STATUS_PAUSED:
drawPausedView(canvas);
break;
case STATUS_FINISHED:
canvas.drawBitmap(finishedImg, 0, 0, null);
break;
} } /**
* 绘制下载中的view
* @param canvas
*/
private void drawDownloadingView(Canvas canvas) {
//绘制灰色圆环
canvas.drawCircle(mXCenter, mYCenter, mRadius - mStrokeWidth/2, mCirclePaint); //绘制进度扇形圆环
RectF oval = new RectF();
//设置椭圆上下左右的坐标
oval.left = mXCenter - mRadius + mStrokeWidth/2;
oval.top = mYCenter - mRadius + mStrokeWidth/2;
oval.right = mXCenter + mRadius - mStrokeWidth/2;
oval.bottom = mYCenter + mRadius - mStrokeWidth/2;
canvas.drawArc(oval, -90, ((float)mProgress / mTotalProgress) * 360, false, mRingPaint); //绘制中间百分比文字
String percentTxt = String.valueOf(mProgress);
//计算文字垂直居中的baseline
Paint.FontMetricsInt fontMetrics = mTxtPaint.getFontMetricsInt();
float baseline = oval.top + (oval.bottom - oval.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
canvas.drawText(percentTxt, mXCenter, baseline, mTxtPaint); } /**
* 绘制暂停时的view
* @param canvas
*/
private void drawPausedView(Canvas canvas) {
//绘制灰色圆环
canvas.drawCircle(mXCenter, mYCenter, mRadius - mStrokeWidth/2, mCirclePaint); //绘制进度扇形圆环
RectF oval = new RectF();
//设置椭圆上下左右的坐标
oval.left = mXCenter - mRadius + mStrokeWidth/2;
oval.top = mYCenter - mRadius + mStrokeWidth/2;
oval.right = mXCenter + mRadius - mStrokeWidth/2;
oval.bottom = mYCenter + mRadius - mStrokeWidth/2;
canvas.drawArc(oval, -90, ((float) mProgress / mTotalProgress) * 360, false, mRingPaint); //绘制中间暂停图标
canvas.drawBitmap(mPausedImg, 0, 0, null);
} /**
* 更新进度
* @param progress
*/
public void setProgress(int progress) {
mProgress = progress;
postInvalidate();
} /**
* 设置下载状态
* @param status
*/
public void setStatus(int status) {
this.mStatus = status;
postInvalidate();
} /**
* 获取下载状态
* @return
*/
public int getStatus() {
return mStatus;
} public static Bitmap big(Bitmap b,float x,float y)
{
int w=b.getWidth();
int h=b.getHeight();
float sx=(float)x/w;
float sy=(float)y/h;
Matrix matrix = new Matrix();
matrix.postScale(sx, sy); // 长和宽放大缩小的比例
Bitmap resizeBmp = Bitmap.createBitmap(b, 0, 0, w,
h, matrix, true);
return resizeBmp;
} }
2、自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources> <declare-styleable name="DownloadPercentView">
<attr name="radius" format="dimension"/>
<attr name="notBeginImg" format="string"/>
<attr name="waitImg" format="string"/>
<attr name="pausedImg" format="string"/>
<attr name="finishedImg" format="string"/>
<attr name="strokeWidth" format="dimension"/>
<attr name="circleColor" format="color"/>
<attr name="ringColor" format="color"/>
</declare-styleable> </resources>
3、使用自定义布局
首先在布局文件中引用:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <com.bbk.lling.downloadpercentdemo.DownloadPercentView
android:id="@+id/downloadView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
custom:notBeginImg="@drawable/ic_no_download"
custom:waitImg="@drawable/ic_wait"
custom:pausedImg="@drawable/ic_pause"
custom:finishedImg="@drawable/ic_finished"
custom:strokeWidth="2dp"
custom:circleColor="#bdbdbd"
custom:radius="18dp"
custom:ringColor="#52ce90"/> </RelativeLayout>
然后我这里在Activity使用一个线程来模拟下载过程来演示:
package com.bbk.lling.downloadpercentdemo; import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View; public class MainActivity extends Activity { public final static int MSG_UPDATE = 1;
public final static int MSG_FINISHED = 2; private DownloadPercentView mDownloadPercentView;
private int mDownloadProgress = 0;
private Handler mHandler = new InnerHandler();
private boolean downloading = false; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDownloadPercentView = (DownloadPercentView) findViewById(R.id.downloadView);
mDownloadPercentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PEDDING
|| mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_PAUSED) {
downloading = true;
mDownloadPercentView.setStatus(DownloadPercentView.STATUS_DOWNLOADING);
//模拟下载
new Thread(new Runnable() {
@Override
public void run() {
while (downloading) {
if(mDownloadProgress == 100) {
mHandler.sendEmptyMessage(MSG_FINISHED);
return;
}
mDownloadProgress += 1;
mHandler.sendEmptyMessage(MSG_UPDATE);
try{
Thread.sleep(100);
} catch (Exception e) {
} }
}
}).start();
} else if(mDownloadPercentView.getStatus() == DownloadPercentView.STATUS_DOWNLOADING){
downloading = false;
mDownloadPercentView.setStatus(DownloadPercentView.STATUS_PAUSED);
}
}
});
} class InnerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_FINISHED:
mDownloadPercentView.setStatus(DownloadPercentView.STATUS_FINISHED);
break;
case MSG_UPDATE:
mDownloadPercentView.setProgress(mDownloadProgress);
break;
}
super.handleMessage(msg);
}
} }
源码下载:https://github.com/liuling07/DownloadPercentDemo
Android中使用自定义View实现下载进度的显示的更多相关文章
- Android中实现自定义View组件并使其能跟随鼠标移动
场景 实现效果如下 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建An ...
- Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题
这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...
- Android中制作自定义dialog对话框的实例
http://www.jb51.net/article/83319.htm 这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继 ...
- Android开发进阶——自定义View的使用及其原理探索
在Android开发中,系统提供给我们的UI控件是有限的,当我们需要使用一些特殊的控件的时候,只靠系统提供的控件,可能无法达到我们想要的效果,这时,就需要我们自定义一些控件,来完成我们想要的效果了.下 ...
- iOS开发小技巧--获取自定义的BarButtonItem中的自定义View的方法(customView)
如果BarButtonItem是通过[[UIBarButtonItem alloc] initWithCustomView:(nonnull UIView *)]方法设置的.某些情况下需要修改BarB ...
- iOS 在UITableViewCell中加入自定义view时view的frame设定注意
由于需要重用同一个布局,于是在cellForRowAtIndexPath中把自定义view加在了cell上,我是这样设定view的frame的 var screenFrame = UIScreen.m ...
- 从一个简洁的进度刻度绘制中了解自定义View的思路流程
先看效果(原谅我的渣像素),进度的刻度.宽度.颜色可以随意设定: [项目github地址: https://github.com/zhangke3016/CircleLoading] 实现起来并不难, ...
- Android中使用AsyncTask实现文件下载以及进度更新提示
Android提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单.相对Handler来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和 ...
- Android 中使用自定义字体的方法
1.Android系统默认支持三种字体,分别为:“sans”, “serif”, “monospace 2.在Android中可以引入其他字体 . <?xml version="1.0 ...
随机推荐
- 咏南IOCP REST中间件
咏南IOCP REST中间件 让DELPHI7也能编写REST服务. 使用IOCP通信+UNIDAC数据库引擎. 客户端跨开发语言调用.
- java中final,finally和finalize的区别
final,finally和finalize的区别: final:最终的意思,可以修饰类,成员变量,成员方法 修饰类,类不能被继承 修饰变量,变量是常量 修饰方法,方法不能被重写 finally:是异 ...
- python 内置函数 map filter reduce lambda
map(函数名,可遍历迭代的对象) # 列组元素全加 10 # map(需要做什么的函数,遍历迭代对象)函数 map()遍历序列得到一个列表,列表的序号和个数和原来一样 l = [2,3,4,5,6, ...
- SQlserver 行转列
列转行编程中很容易碰到,小弟在此总结下, 行转列暂时还没遇到,遇到再补充. 列转行: , , , , 以上都是以逗号分隔,分隔符可以自定义.
- ssh: connect to host gihub.com port 22: Connection timed out
方案1(本人使用此方案,问题得已解决): 可能是ssh-server未安装或者未启动.我的ubuntu 12.04 默认只安装了openssh-client,并没有安装server. 运行 ps -e ...
- cocos2d-x 之 CCArray 源码分析(2)
cocos2d-x 自己实现了一个数组CCArray ,下面我们来分析一下CCArray的源码 CCArray继承CCObject,所以,CCArray也具有引用计数功能和内存自动管理功能. 数组的源 ...
- 团队作业week8
每个团队编写一个团队项目的功能规格说明书.
- App开发的过程
直播App开发的过程 第一步:分解直播App的功能,我们以X客为例 视频直播功能,这是一款直播App最主要的功能,要能支持视频直播RTMP推流,使画面传输流畅.清晰(美颜后的清晰,你懂的聊天功能,用户 ...
- tcp/ip的一些概念
MTU,即Maximum Transmission Unit(最大传输单元),此值设定TCP/IP协议传输数据报时的最大传输单元.以太网的MTU值是1500 bytes. 首先计算最大的IP包中IP净 ...
- 添加App启动页面
记录下自己在设置app启动页面时遇到的问题. 先写下自己完整的步骤吧. iPhone Portrait iOS 8-Retina HD 5.5 (1242×2208) @3xiPhone Portra ...