自定义view可以实现很多我们想要的效果,当前我使用自定义view实现了一个圆弧进度条,具体效果如下:
首先我们创建自定义控件类CircleProgressbar继承自view,在values目录下创建它的属性xml:circle_progressbar_attrs,配置相关属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="circle_progressbar">
<attr name="BigCircleRadius" format="dimension"/>
<attr name="NormalCircleRadius" format="dimension"/>
<attr name="SmallCircleRadius" format="dimension"/>
<attr name="SmallerCircleRadius" format="dimension"/>
<attr name="BigCircleColor" format="color"/>
<attr name="NormalCircleColor" format="color"/>
<attr name="SmallCircleColor" format="color"/>
<attr name="SmallerCircleColor" format="color"/>
</declare-styleable>
</resources>
然后开始创建构造函数:
private Paint mPaint;
private Paint mPaint2;
private float bigCircleRadius;
private float normalCircleRadius;
private float smallCircleRadius;
private float smallerCircleRadius;
private int bigCircleColor;
private int normalCircleColor;
private int smallCircleColor;
private int smallerCircleColor;
private int progress; //进度
private ProgressLisener mlistener;
private int status = 0;
public CircleProgressbar(Context context) {
this(context, null);
}
public CircleProgressbar(Context context, AttributeSet attrs) {
super(context, attrs);
initStyledAttrs(attrs);
initPaint();
}
private void initStyledAttrs(AttributeSet attrs) {
TypedArray array = null;
try {
array = getContext().obtainStyledAttributes(attrs, R.styleable.circle_progressbar);
bigCircleRadius = array.getDimension(R.styleable.circle_progressbar_BigCircleRadius, DptoPx(70));
normalCircleRadius = array.getDimension(R.styleable.circle_progressbar_NormalCircleRadius, DptoPx(60));
smallCircleRadius = array.getDimension(R.styleable.circle_progressbar_SmallCircleRadius, DptoPx(50));
smallerCircleRadius = array.getDimension(R.styleable.circle_progressbar_SmallerCircleRadius, DptoPx(40));
bigCircleColor = array.getColor(R.styleable.circle_progressbar_BigCircleColor, Color.parseColor("#033649"));
normalCircleColor = array.getColor(R.styleable.circle_progressbar_NormalCircleColor,Color.parseColor("#036564"));
smallCircleColor = array.getColor(R.styleable.circle_progressbar_SmallCircleColor, Color.parseColor("#CDB380"));
smallerCircleColor = array.getColor(R.styleable.circle_progressbar_SmallerCircleColor,Color.parseColor("#E8DDCB"));
} catch (Exception e) {
e.printStackTrace();
bigCircleRadius = DptoPx(30);
normalCircleRadius = DptoPx(18);
smallCircleRadius = DptoPx(6);
smallerCircleRadius = DptoPx(3);
bigCircleColor = Color.parseColor("#E8DDCB");
normalCircleColor = Color.BLUE;
smallCircleColor = Color.RED;
smallerCircleColor = Color.YELLOW;
} finally {
if (array != null) {
array.recycle();
}
}
}
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);//抗锯齿
mPaint.setDither(true); //防抖动
mPaint.setStrokeWidth(20);
mPaint.setStyle(Paint.Style.STROKE);
mPaint2 = new Paint();
mPaint2.setAntiAlias(true);//抗锯齿
mPaint2.setDither(true); //防抖动
mPaint2.setStrokeWidth(3);
mPaint2.setTextSize(40);
mPaint2.setColor(Color.GREEN);
}
写好构造函数后,重写onMeasure方法,测量控件大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 1000;//设定一个最小值
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED || heightMeasureSpec == MeasureSpec.AT_MOST || heightMeasureSpec == MeasureSpec.UNSPECIFIED) {
width = widthSize / 2;
} else { //至少有一个为确定值,要获取其中的最小值
if (widthMode == MeasureSpec.EXACTLY) {
width = Math.min(widthSize, width);
}
if (heightMode == MeasureSpec.EXACTLY) {
width = Math.min(heightSize, width);
}
}
setMeasuredDimension(width, width);
}
重写onDraw方法之前,创建接口ProgressLisener,监听进度加载情况,用于接口回调:
protected interface ProgressLisener {
void OnPregressEnd();
}
public void setOnProgressListener(ProgressLisener progressListener) {
this.mlistener = progressListener;
}
//获得当前进度百分比
private String getPersentProgress(int progress) {
double x = progress*1.0/360;
int y = (int)(x*100);
return y+"%";
}
创建公有方法setProgress,方便外面更新进度:
public void setProgress(int progress) {
this.progress = progress;
}
最后重写关键的onDraw方法,根据进度绘制ui:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
RectF rectFBig = new RectF(getWidth() / 2 - bigCircleRadius, getHeight() / 2 - bigCircleRadius, getWidth() / 2 + bigCircleRadius, getHeight() / 2 + bigCircleRadius);
mPaint.setColor(bigCircleColor);
//绘制大圆弧
canvas.drawArc(rectFBig, 0, progress, false, mPaint);
canvas.restore();
canvas.save();
RectF rectFNormal = new RectF(getWidth() / 2 - normalCircleRadius, getHeight() / 2 - normalCircleRadius, getWidth() / 2 + normalCircleRadius, getHeight() / 2 + normalCircleRadius);
mPaint.setColor(normalCircleColor);
//绘制中圆弧
canvas.drawArc(rectFNormal, 180, progress, false, mPaint);
canvas.restore();
canvas.save();
RectF rectFSmall = new RectF(getWidth() / 2 - smallCircleRadius, getHeight() / 2 - smallCircleRadius, getWidth() / 2 + smallCircleRadius, getHeight() / 2 + smallCircleRadius);
mPaint.setColor(smallCircleColor);
//绘制小圆弧
canvas.drawArc(rectFSmall,90, progress, false, mPaint);
canvas.restore();
canvas.save();
RectF rectFSmaller = new RectF(getWidth() / 2 - smallerCircleRadius, getHeight() / 2 - smallerCircleRadius, getWidth() / 2 + smallerCircleRadius, getHeight() / 2 + smallerCircleRadius);
mPaint.setColor(smallerCircleColor);
//绘制最小圆弧
canvas.drawArc(rectFSmaller,270, progress, false, mPaint);
canvas.restore();
//绘制中间进度显示
if(status == 0) {
canvas.drawText(getPersentProgress(progress),getWidth()/2-24,getHeight()/2+16,mPaint2);
}else {
canvas.drawText("OK", getWidth() / 2 - 24, getHeight() / 2 + 16, mPaint2);
}
postInvalidate();
//进度在360时,加载完成
if(progress==360){
progress = 361;
status = 1;
mlistener.OnPregressEnd();
}
}
好了,自定义view就写好了,实现得非常简单,下面我们来看一下在activity中是怎么使用的。
首先是xml文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.benhuan.mycircleprocessbardemo.CircleProgressbar
android:id="@+id/cp_cpbar"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<Button
android:id="@+id/bt_load"
android:text="load"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
在activity中,使用一个线程来模拟下载的情况,在下载完成后,终止线程,打印吐司,具体代码如下:
package com.benhuan.mycircleprocessbardemo;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private CircleProgressbar cpbar;
private Button btstart;
private int progress;
private MyThread myThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cpbar = (CircleProgressbar) findViewById(R.id.cp_cpbar);
cpbar.setOnProgressListener(new CircleProgressbar.ProgressLisener() {
@Override
public void OnPregressEnd() {
myThread.interrupted();
Toast.makeText(MainActivity.this,"加载完毕",Toast.LENGTH_SHORT).show();
}
});
myThread = new MyThread();
btstart = (Button) findViewById(R.id.bt_load);
btstart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!myThread.isAlive()) {
myThread.start();
}
}
});
}
class MyThread extends Thread {
@Override
public void run() {
super.run();
while(!this.isInterrupted()) {
if(progress<=360)
cpbar.setProgress(progress++);
SystemClock.sleep(10);
}
}
}
}
全部代码就是这样了,我们看到代码不多,使用起来也十分方便,我们还可以ui和监听情况进行扩展,这里就不一一展开了。感谢您的阅读,有什么不足之处欢迎指正。
源码点此下载