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

Android 绘制圆形进度条

2015-09-02 17:45 465 查看

Android 绘制圆形进度条

最近项目上有一些需求,需要绘制圆形的进度条满足设计上和交互上的需求:



实现思路

在画布上直接绘制View,需要了解一下几点

1.需要画一个圆

2.圆圈上有不同进度的颜色

3.圆圈中有进度数字的展示

4.圆圈中间还有可以自定义不同文案提示

一、画圆

需要使用Canvas的该方法

public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
@NonNull Paint paint) {
drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
paint);
}


如下:

// 设置画笔相关属性
mPaint.setAntiAlias(true);
mPaint.setColor(Color.rgb(0xe9, 0xe9, 0xe9));
canvas.drawColor(Color.TRANSPARENT);
mPaint.setStrokeWidth(mCircleLineStrokeWidth);
mPaint.setStyle(Style.STROKE);
// 位置
mRectF.left = mCircleLineStrokeWidth / 2; // 左上角x
mRectF.top = mCircleLineStrokeWidth / 2; // 左上角y
mRectF.right = width - mCircleLineStrokeWidth / 2; // 左下角x
mRectF.bottom = height - mCircleLineStrokeWidth / 2; // 右下角y

// 绘制圆圈,进度条背景
canvas.drawArc(mRectF, -90, 360, false, mPaint);


此时画出了默认的背景圆圈:



二、画进度圆弧

其实实现很简单,换另外一种颜色同样在画布上画出即可,支持此时画的不是360°,而是通过进度计算出来的一个圆弧。

mPaint.setColor(Color.rgb(0xf8, 0x60, 0x30));
canvas.drawArc(mRectF, -90, ((float) mProgress / mMaxProgress) * 360, false, mPaint);


如上即可,此时mProgress / mMaxProgress = 80/100;即可绘制出如下效果



三、画中间进度百分比

其实要用到Canvas中绘制文本的方法:

public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
}


如下:

// 绘制进度文案显示
mPaint.setStrokeWidth(mTxtStrokeWidth);
String text = mProgress + "%";
int textHeight = height / 4;
mPaint.setTextSize(textHeight);
int textWidth = (int) mPaint.measureText(text, 0, text.length());
mPaint.setStyle(Style.FILL);
canvas.drawText(text, width / 2 - textWidth / 2, height / 2 + textHeight / 2, mPaint);


主要要计算好画的位置,drawText中对应就是相关的位置,相当于居中显示进度百分比文案。效果如下:



四、画圆圈中间提示文案

方法同三,只不过要计算出画的位置即可,效果图如下:



五、总结

其实很多自定义的View都可以用Canvas直接画出来,如果项目上有类似这样的需求,可以先研究Canvas的使用和原理。

最后附上源码:

public class CircleProgressView extends View {

private static final String TAG = "CircleProgressBar";

private int mMaxProgress = 100;

private int mProgress = 30;

private final int mCircleLineStrokeWidth = 8;

private final int mTxtStrokeWidth = 2;

// 画圆所在的距形区域
private final RectF mRectF;

private final Paint mPaint;

private final Context mContext;

private String mTxtHint1;

private String mTxtHint2;

public CircleProgressView(Context context, AttributeSet attrs) {
super(context, attrs);

mContext = context;
mRectF = new RectF();
mPaint = new Paint();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = this.getWidth();
int height = this.getHeight();

if (width != height) {
int min = Math.min(width, height);
width = min;
height = min;
}

// 设置画笔相关属性
mPaint.setAntiAlias(true);
mPaint.setColor(Color.rgb(0xe9, 0xe9, 0xe9));
canvas.drawColor(Color.TRANSPARENT);
mPaint.setStrokeWidth(mCircleLineStrokeWidth);
mPaint.setStyle(Style.STROKE);
// 位置
mRectF.left = mCircleLineStrokeWidth / 2; // 左上角x
mRectF.top = mCircleLineStrokeWidth / 2; // 左上角y
mRectF.right = width - mCircleLineStrokeWidth / 2; // 左下角x
mRectF.bottom = height - mCircleLineStrokeWidth / 2; // 右下角y

// 绘制圆圈,进度条背景
canvas.drawArc(mRectF, -90, 360, false, mPaint);
mPaint.setColor(Color.rgb(0xf8, 0x60, 0x30)); canvas.drawArc(mRectF, -90, ((float) mProgress / mMaxProgress) * 360, false, mPaint);

// 绘制进度文案显示 mPaint.setStrokeWidth(mTxtStrokeWidth); String text = mProgress + "%"; int textHeight = height / 4; mPaint.setTextSize(textHeight); int textWidth = (int) mPaint.measureText(text, 0, text.length()); mPaint.setStyle(Style.FILL); canvas.drawText(text, width / 2 - textWidth / 2, height / 2 + textHeight / 2, mPaint);

if (!TextUtils.isEmpty(mTxtHint1)) {
mPaint.setStrokeWidth(mTxtStrokeWidth);
text = mTxtHint1;
textHeight = height / 8;
mPaint.setTextSize(textHeight);
mPaint.setColor(Color.rgb(0x99, 0x99, 0x99));
textWidth = (int) mPaint.measureText(text, 0, text.length());
mPaint.setStyle(Style.FILL);
canvas.drawText(text, width / 2 - textWidth / 2, height / 4 + textHeight / 2, mPaint);
}

if (!TextUtils.isEmpty(mTxtHint2)) {
mPaint.setStrokeWidth(mTxtStrokeWidth);
text = mTxtHint2;
textHeight = height / 8;
mPaint.setTextSize(textHeight);
textWidth = (int) mPaint.measureText(text, 0, text.length());
mPaint.setStyle(Style.FILL);
canvas.drawText(text, width / 2 - textWidth / 2, 3 * height / 4 + textHeight / 2, mPaint);
}
}

public int getMaxProgress() {
return mMaxProgress;
}

public void setMaxProgress(int maxProgress) {
this.mMaxProgress = maxProgress;
}

public void setProgress(int progress) {
this.mProgress = progress;
this.invalidate();
}

public void setProgressNotInUiThread(int progress) {
this.mProgress = progress;
this.postInvalidate();
}

public String getmTxtHint1() {
return mTxtHint1;
}

public void setmTxtHint1(String mTxtHint1) {
this.mTxtHint1 = mTxtHint1;
}

public String getmTxtHint2() {
return mTxtHint2;
}

public void setmTxtHint2(String mTxtHint2) {
this.mTxtHint2 = mTxtHint2;
}
}


Xml中配置:

<com.jackshy.demo.view.CircleProgressBar
android:id="@+id/circleProgressbar"
android:layout_width="74dp"
android:layout_height="74dp"
android:layout_centerInParent="true" />


MainActivity中使用:

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

import com.jackshy.demo.view.CircleProgressBar;

public class MainActivity extends Activity {

private CircleProgressBar mCircleBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initViews();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

private void initViews() {

mCircleBar = (CircleProgressBar) findViewById(R.id.circleProgressbar);

mCircleBar.setProgress(80);

}

}


上述还可以做成进度条的形式,这时候需要启动非UI线程调用此方法即可:

public void setProgressNotInUiThread(int progress) {
this.mProgress = progress;
this.postInvalidate();
}


待续。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: