您的位置:首页 > 移动开发 > Android开发

Android自定义View:进度条+冒泡文本

2017-08-18 16:34 357 查看
简介

最近看到有这样的需求:显示进度条,描述文本显示在进度条的刻度上面。正好练练手,回顾下自定义View知识。



分析

通过上图,我们可以看到,该UI显示了文本,而文本显示在一张图片中,有一个默认的进度条和根据实际进度显示的进度条。我们可以将其拆分成4个组成部分:

(1)图片,作为文本的背景图,这个背景图应该伸缩不失真,建议用.9图;

(2)文本,有颜色和大小,显示在图片上,居中显示;

(3)默认进度条,有颜色和宽高;

(4)真正的进度条:有颜色和进度值、宽高。它比较特殊的是当进度不等于100%时,左边是圆弧,右边是直线型(没有圆角)。

代码

首先在构造函数初始化画笔,在onSizeChanged中确定控件的宽高,设置画笔的颜色,然后在onDraw中开始绘制内容

private Context mContext;
/**
* 背景图画笔
*/
private Paint mBackgroundPaint;
/**
* 进度画笔
*/
private Paint mProgressPaint;
/**
* 文本画笔
*/
private Paint mTextPaint;
/**
* 图片画笔
*/
private Paint mPicturePaint;
/**
* 背景矩形颜色
*/
private int mBackgroundColor = Color.BLACK;
/**
* 进度矩形颜色
*/
private int mProgressColor = Color.GRAY;
/**
* 文本颜色
*/
private int mTextColor = Color.BLACK;
/**
* 文本大小
*/
private int mTextSize = 28;
/**
* 控件宽高:控件必须在布局中指定宽高大小
*/
private int mWidth;
private int mHeight;
/**
* 进度矩形高度
*/
private int mProgressHeight = 10;
/**
* 图片宽高
*/
private int mPicWidth;
private int mPicHeight;
/**
* 矩形4个角的半径坐标,左上,右上,右下,左下(顺时针)
*/
private float[] mRadiusArr = new float[]{0f,0f,0f,0f,0f,0f,0f,0f};
/**
* 进度
*/
private float mProgress;
/**
* 文本
*/
private String mText;

public ProgressBubbleView(Context context) {
super(context);
initView(context);
}

public ProgressBubbleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context);
}

public ProgressBubbleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}

private void initView(Context context){
mContext = context;

mBackgroundPaint = new Paint();
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setStrokeWidth(1);

mBackgroundPaint.setAntiAlias(true);

mProgressPaint = new Paint();
mProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mProgressPaint.setStrokeWidth(2);
mProgressPaint.setAntiAlias(true);

mTextPaint = new Paint();
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);

mPicturePaint = new Paint();
mPicturePaint.setStyle(Paint.Style.STROKE);
mPicturePaint.setAntiAlias(true);
setLayerType(LAYER_TYPE_SOFTWARE,null);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;

mBackgroundPaint.setColor(mBackgroundColor);
mProgressPaint.setColor(mProgressColor);
mTextPaint.setColor(mTextColor);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//绘制文本背景框
drawPicture(canvas);
//绘制文本
drawText(canvas);
//将原点坐标移到文本之下
canvas.translate(0,mPicHeight-28);//因为图片底部有留白,导致图片与进度条的距离看起来偏大,所以减去一段距离
//绘制背景圆角矩形
drawBackgroud(canvas);
//绘制进度矩形圆角
drawProgress(canvas);
}


绘制图片

/**
* 绘制文本背景框
* @param canvas
*/
private void drawPicture(Canvas canvas){
if(this.mProgress == 0)
return;
float percent = this.mProgress / 100 * 1.0f;
int width = (int) (percent * mWidth);
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.infowindow_bg);
mPicWidth = bitmap.getHeight();
mPicHeight = bitmap.getWidth();
int pos = width - mPicWidth/2 - 13;
canvas.drawBitmap(bitmap,pos,0,mPicturePaint);

}


绘制文本

/**
* 绘制文本
* @param canvas
*/
private void drawText(Canvas canvas){
if(this.mProgress == 0)
return;
float percent = this.mProgress / 100 * 1.0f;
int width = (int) (percent * mWidth);
float length = mTextPaint.measureText(mText);
canvas.drawText(mText,width-length/2,mPicHeight/3,mTextPaint);
}


绘制默认进度条

/**
* 绘制背景矩形圆角
* @param canvas
*/
private void drawBackgroud(Canvas canvas){
RectF rectF = new RectF();
rectF.left = 0;
rectF.top = 0;
rectF.right = mWidth;
rectF.bottom = mProgressHeight;

allRoundRadius();
Path path = new Path();
path.addRoundRect(rectF, mRadiusArr,Path.Direction.CW);
canvas.drawPath(path,mBackgroundPaint);
}


这里利用path类的addRoundRect方法的第2个参数float[] radii来实现矩形四个角是圆角还是直角效果。radii是一个大小为8的数组,2个元素为1对,表示矩形的一个角,分别为左上,右上,右下,左下(顺时针)。

绘制进度条

/**
* 绘制进度矩形圆角(只有左上和左下是圆角)
* @param canvas
*/
private void drawProgress(Canvas canvas){
if(this.mProgress == 0)
return;
float percent = this.mProgress / 100 * 1.0f;
int width = (int) (percent * mWidth);

RectF rectF = new RectF();
rectF.left = 0;
rectF.top = 0;
rectF.right = width;
rectF.bottom = mProgressHeight;

if (this.mProgress < 100){
mRadiusArr[0] = 20;
mRadiusArr[1] = 20;
mRadiusArr[2] = 0;
mRadiusArr[3] = 0;
mRadiusArr[4] = 0;
mRadiusArr[5] = 0;
mRadiusArr[6] = 20;
mRadiusArr[7] = 20;
}else{
allRoundRadius();
}
Path path = new Path();
path.addRoundRect(rectF,mRadiusArr,Path.Direction.CW);
canvas.drawPath(path,mProgressPaint);
}

/**
* 4个角都是圆角
*/
private void allRoundRadius(){
mRadiusArr[0] = 20;
mRadiusArr[1] = 20;
mRadiusArr[2] = 20;
mRadiusArr[3] = 20;
mRadiusArr[4] = 20;
mRadiusArr[5] = 20;
mRadiusArr[6] = 20;
mRadiusArr[7] = 20;
}


在drawProgress中,当进度不等于100%时,左边是圆弧,右边是直线型,所以设置左上、左下的圆角半径为20,其他2个角半径为0,从而实现左边圆弧,右边直线的圆角矩形效果。

开放的接口

/**
* 设置是否矩形4个角都是圆角
* @param isAllRound
*/
public void setFourRoundRect(boolean isAllRound){
if (isAllRound){
allRoundRadius();
}
invalidate();
}

/**
* 设置进度值0-100
* @param progress
*/
public void setProgress(float progress){
this.mProgress = progress;
invalidate();
}

/**
* 设置文本
* @param text
*/
public void setText(String text){
this.mText = text;
invalidate();
}

public void  setBackgroundColor(int backgroundColor){
this.mBackgroundColor = backgroundColor;
invalidate();
}

public void  setProgressColor(int progressColor){
this.mProgressColor = progressColor;
invalidate();
}

public void  setTextColor(int textColor){
this.mTextColor = textColor;
invalidate();
}


效果图



最后

当然,这只是粗略的实现,还是有些问题遗留的。比如进度为0或100时,文本和文本背景图如何显示;进度显示是静态的,如何动态实现显示呢等等。我们可以根据具体的需求去控制,我就不一一描述了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: