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

android之自定义带文本的圆角进度条

2016-05-26 11:02 399 查看
自定义圆角进度条以及颜色渐变的进度条

先上图,给个直观印象



一、先来看看渐变的圆角

private void init(AttributeSet attrs) {
mRadius = (int) ((getScreenSize(context).x * 0.6f) / 2);//屏幕的1/4
initPaint();
}

private void initPaint() {
// 初始化画笔对象
mPaint.setStyle(Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setDither(true);//设置抖动
mPaint.setStrokeCap(Cap.ROUND);

mPaintUnReach.setStyle(Style.STROKE);
mPaintUnReach.setAntiAlias(true);
mPaintUnReach.setDither(true);
mPaintUnReach.setStrokeCap(Cap.ROUND);
// 设置画笔颜色和宽度
mPaintUnReach.setColor(mUnReachBarColor);

mTextPaint.setStyle(Style.FILL);
mTextPaint.setAntiAlias(true);
mTextPaint.setDither(true);
}
1、初始化画笔及画圆的半径,半径非常重要,会影响圆的宽高,读者可根据自己需要提供一个公用方法设置或者自定义属性实现,现只是为了讲解,取屏幕w的1/4为半径

2、初始化画笔,圆角主要是setStrokeCap(Cap.ROUND)来设置的,而设置抖动setDither()这个大概意思是保证画图的清晰度已经平滑度,抗锯齿setAntiAlias();表示画出来的视图不会有锯齿

二、再来看看其onMeasure和onDraw()方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 两个画笔的最大宽度
int paintWidth = Math.max(mUnReachBarWidth, mReachBarWidth);
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);

if (wMode == MeasureSpec.AT_MOST && hMode == MeasureSpec.AT_MOST) {
wSize = mRadius * 2 + (paintWidth / 2) * 2;
hSize = mRadius * 2 + (paintWidth / 2) * 2;
} else if (wMode == MeasureSpec.AT_MOST) {
wSize = mRadius * 2 + (paintWidth / 2) * 2;
} else if (hMode == MeasureSpec.AT_MOST) {
hSize = mRadius * 2 + (paintWidth / 2) * 2;
}
if (0 >= wSize) {
wSize = mRadius * 2;
}

if (0 >= hSize) {
hSize = mRadius * 2;
}

// 获取宽度和高度的最小值,作为当前view的宽度和高度
mSize = Math.min(wSize, hSize);
// 设置进度条的大小:整个view的大小
setMeasuredDimension(mSize, mSize);

// 设置画笔宽度
mMaxPaintWidth = paintWidth;
// 计算进度条的半径 画笔是从画笔的宽度中间开始画的----
// 、、此处有个坑,若是有进入到二级页面再回来,可能视图会变小,因为每次半径测量时都会减小,
// 根据需要半径最好放在初始化时设置,不要让它变化
mRadius = (mSize - (mMaxPaintWidth / 2) * 2) / 2;

mPaint.setStrokeWidth(mMaxPaintWidth);
mPaintUnReach.setStrokeWidth(mMaxPaintWidth);
}


@Override
protected void onDraw(Canvas canvas) {
// 在save和restore之间的代码可以进行canvas的平移、缩放等操作
canvas.save();
// 画布旋转120度
canvas.rotate(115, mSize / 2, mSize / 2);
int progressMax = getMax();
// 绘制unreachedBar
// 绘制reachBar :画布旋转115度,所以是从115度开始,从0开始,从 5度开始画,就是120
canvas.drawArc(new RectF(mMaxPaintWidth / 2, mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2), 5, progressMax * 1.0f / progressMax * 300, false, mPaintUnReach);

//        canvas.drawCircle(mSize / 2, mSize / 2, mRadius, mPaintUnReach);
// 设置画笔颜色:绘制过程中会渐变 mReachBarColor是数组起始颜色和最终颜色,渐变的过程
SweepGradient sg = new SweepGradient(mSize / 2, mSize / 2, mReachBarColor, null);
mPaint.setShader(sg);
//        sg.setLocalMatrix();除了旋转画布外,也可根据这个矩阵来旋转起始角度
// 计算当前进度对应的角度
float sweepAngle = mCurrentProgress * 1.0f / progressMax * 300;
// 绘制reachBar :原始0度角是沿x轴方向的旋转115度之后,0角度指的就是115度的位置,
// 起始角度为5是因为画弧度的颜色值是从一半开始画的,所以后一半圆会取前边的颜色值,导致不一致,所以从5度开始画,可根据画笔宽度的一半来设置
canvas.drawArc(new RectF(mMaxPaintWidth / 2, mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2), 5, sweepAngle, false, mPaint);
canvas.restore();
drawText(canvas);
}

private void drawText(Canvas canvas) {
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTextSize(dp2px(40));
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);// 设置粗体
float weightWidth = mTextPaint.measureText(weightValue);
float weightTextSize = mTextPaint.getTextSize();
canvas.drawText(weightValue, mSize / 2 - weightWidth / 2, mSize / 2 + weightTextSize / 2 - dp2px(5), mTextPaint);

mTextPaint.setTypeface(Typeface.DEFAULT);//设置常规字体
// 绘制单位(Kg)
mTextPaint.setTextSize(dp2px(12));

// 此处多减去了一个textSize的一半,因为绘制text的时候
canvas.drawText(unit, mSize / 2 + weightWidth / 2, mSize / 2 + weightTextSize / 2 - dp2px(5), mTextPaint);

// 绘制“体重状态”
mTextPaint.setTextSize(dp2px(12));
weightWidth = mTextPaint.measureText(weightStatus);
// 以下也可以获取大小范围
//        mPaint.getTextBounds(text, 0, text.length(), mRect);//
//        int x = (getWidth() / 2) - mRect.centerX();// 文本的内容区域中心点开始绘制
//        int y = (getHeight() / 2) - mRect.centerY();
float weightStatusTextSize = mTextPaint.getTextSize();
canvas.drawText(weightStatus, mSize / 2 - weightWidth / 2, mSize / 2 - dp2px(12) - weightTextSize / 2, mTextPaint);

// 绘制“体重目标”
mTextPaint.setTextSize(dp2px(12));
weightWidth = mTextPaint.measureText(weightTargetDesc);
float targetTextSize = mTextPaint.getTextSize();
canvas.drawText(weightTargetDesc, mSize / 2 - weightWidth / 2, mSize / 2 + weightTextSize, mTextPaint);
}


1、主要是测量视图的宽高,然后通过setMeasuredimension来设置其测量的宽高

高能预警:此处有个坑,天大的坑 :mRadius 在这里不断的赋值,由于onMeasure不单单执行一次,在测量期间会执行多次,导致mRadius一直在变化,导致逐渐变小或变大,导致视图可能会变的更大或视图不可见,所以这种初始化的赋值,建议放在初始化或ondraw中,就不会有这种问题。。。这里出现问题就直接拿出来跟大家分享,代码我也没改正,圆角渐变代码我并没有改正,但是色环的已经改正了,代码都差不多,自行参考

2、onDraw方法中 首先因为起始角度(0角度)是x轴方向,所以要旋转画布到自己所需要的开始绘制的地方,这里将画布旋转115,即绘制的起始点;此外由于画笔是从画笔的宽度中心点开始绘制的所以mRadius半径mSize减去画笔跨度的一半再除以2,就是画圆的半径 即(

mRadius = (mSize - (mMaxPaintWidth / 2) * 2) / 2

,而后drawArc就是画弧,第一次调用就是画弧的背景,第二次才是画弧的进度,画弧的时候起始角度是从5开始,因为,画笔是从中间开始的,而由于是渐变色(SweepGradent类控制的)前一半圆弧的颜色是往前取的所以会导致有色差,所以起始角度往后一移动5个角度(可根据画笔宽度的一半来取),这也是为什么只旋转115而不是120角度的原因。

二、色环的代码跟圆弧的差不多,依葫芦画瓢,相信读者都有举一反三的能力,这里就不再讲解,需要的可下载demo查看源码

demo:http://download.csdn.net/detail/zhongwn/9531575
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  色环 渐变圆弧