自定义控件 《进度条,统计圆环图》从0基础开始,备注详细,还有其他小技巧 (后续会不断的更新优化)
说明:外环进度条的颜色 、宽度、底色;百分比的字体、大小、颜色;文字的大小、颜色、进度条动态加载的快慢都可以自定义,在代码中设置 或者 布局中配置。
一、自定义控件View(有详细的注释:小白级别也可看懂)
注释1:TypedArray的使用场景之一,就是上述的自定义View,会随着 Activity的每一次Create而Create,因此,需要系统频繁的创建array,对内存和性能是一个不小的开销,如果不使用池模式,每次都让GC来回收,很可能就会造成OutOfMemory。
这就是使用池+单例模式的原因,这也就是为什么官方文档一再的强调:使用完之后一定 recycle,recycle,recycle。
注释2:postIvalidate 刷新界面
<span style="font-size:12px;">/**
* 作者:JXF
* 创建时间:2016/3/31 下午 2:18
* 描述:团队统计圆环自定义控件
*/
public class RoundProgressBar extends View {
/**
* 画笔对象的引用
*/
private Paint paint;
/**
* 当前的进度
*/
private int progress;
/**
* 进度条样式:空心
*/
public static final int STROKE = 0;
/**
* 进度条样式:实心
*/
public static final int FILL = 1;
public RoundProgressBar(Context context) {
this(context, null);
}
public RoundProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
//获取自定义属性和默认值
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor,getResources().getColor(R.color.stat_background_blue2));
roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, getResources().getColor(R.color.switch_ios7_color));
textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, getResources().getColor(R.color.switch_ios7_color));
textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 15);
roundWidth1 = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth1, 8);
max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);
textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);
style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0);
roundText=mTypedArray.getString(R.styleable.RoundProgressBar_roundText);
roundTextColor=mTypedArray.getColor(R.styleable.RoundProgressBar_roundTextColor, getResources().getColor(R.color.black_dark));
roundTextSize=mTypedArray.getDimension(R.styleable.RoundProgressBar_roundTextSize, 15);
/*防止造成OutOfMemory*/
mTypedArray.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
*画最外层的大圆
*/
int centre = getWidth() / 2;//获取圆心的x坐标
int radius = (int) (centre - roundWidth1 / 2);//圆环的半径
paint.setColor(roundColor);//设置圆环的颜色
paint.setStyle(Paint.Style.STROKE);//设置空心
paint.setStrokeWidth(roundWidth1);//设置圆环的宽度
paint.setAntiAlias(true); //消除锯齿
canvas.drawCircle(centre, centre, radius, paint);
/**
* 画进度百分比
*/
paint.setStrokeWidth(0);
paint.setColor(textColor);
paint.setTextSize(textSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);//设置字体
int percent = (int) (((float) progress / (float) max) * 100); //中间的进度百分比,先转换成float在进行除法运算,不然都为0
float textWidth = paint.measureText(percent + "%"); //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
if (textIsDisplayable && percent != 0 && style == STROKE) {
canvas.drawText(percent + "%", centre - textWidth/ 2, centre + textSize / 2, paint);//画出进度百分比
}
/**
* 画进度百分比下面的文字
*/
paint.setStrokeWidth(0);
paint.setColor(roundTextColor);
paint.setTextSize(roundTextSize);
if(roundText==null || roundText.equals("")){
roundText="默认";
}
float text1Width = paint.measureText(roundText);
if(textIsDisplayable && percent != 0 && style == STROKE){
canvas.drawText(roundText, centre - text1Width / 2, centre + textSize + textSize/2, paint); //画出进度百分比
}
/**
* 画圆弧 ,画圆环的进度
*/
//设置进度是实心还是空心
paint.setStrokeWidth(roundWidth1);//设置圆环的宽度
paint.setColor(roundProgressColor);//设置进度点饿颜色
RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius);//用于定义的圆弧的形状和大小的界限
switch (style) {
case STROKE: {
paint.setStyle(Paint.Style.STROKE);
canvas.drawArc(oval, 0, 360 * progress / max, false, paint); //fase 实心
break;
}
case FILL: {
paint.setStyle(Paint.Style.FILL_AND_STROKE);
if (progress != 0)
canvas.drawArc(oval, 0, 360 * progress / max, true, paint); //根据进度画圆弧 空心
break;
}
}
/**
* 进度条达到满的时候触发事件
*/
if (progress == max && null != onLoadFinish) {
onLoadFinish.onLoadFinished();
}
}
/*synchronized保证在同一时刻最多只有一个线程执行该段代码*/
public synchronized int getMax() {
return max;
}
/**
* 设置进度的最大值
*
* @param max
*/
public synchronized void setMax(int max) {
if (max < 0) {
throw new IllegalArgumentException("max not less than 0");
}
this.max = max;
}
/**
* 获取进度.需要同步
*
* @return
*/
public synchronized int getProgress() {
return progress;
}
/**
* 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
* 刷新界面调用postInvalidate()能在非UI线程刷新
*
* @param progress
*/
public synchronized void setProgress(int progress) {
if (progress < 0) {
throw new IllegalArgumentException("progress not less than 0");
}
if (progress > max) {
progress = max;
}
if (progress <= max) {
this.progress = progress;
postInvalidate();//刷新界面
//postInvalidateDelayed();
}
}
/**
* 一定一个接口
*/
public interface OnLoadFinishListener {
public void onLoadFinished();
}
/**
* 初始化接口变量
*/
OnLoadFinishListener onLoadFinish = null;
/**
* 自定义控件的自定义事件
*
* @param listener 接口类型
*/
public void setOnLoadFinishListener(OnLoadFinishListener listener) {
onLoadFinish = listener;
}
/*********************************控件属性(开始)************************************/
/**
* 圆环的中的文字
*/
private String roundText;
/**
* 圆环的中的文字颜色
*/
private int roundTextColor;
/**
* 圆环的中的文字大小
*/
private float roundTextSize;
/**
* 圆环的颜色
*/
private int roundColor;
/**
* 圆环进度的颜色
*/
private int roundProgressColor;
/**
* 中间进度百分比的字符串的颜色
*/
private int textColor;
/**
* 中间进度百分比的字符串的字体大小
*/
private float textSize;
/**
* 圆环的宽度
*/
private float roundWidth1;
/**
* 最大的进度
*/
private int max;
/**
* 是否显示中间进度
*/
private boolean textIsDisplayable;
/**
* 进度的风格:实心或者空心
*/
private int style;
public String getRoundText() {
return roundText;
}
public void setRoundText(String roundText) {
this.roundText = roundText;
}
public int getRoundTextColor() {
return roundTextColor;
}
public void setRoundTextColor(int roundTextColor) {
this.roundTextColor = roundTextColor;
}
public float getRoundTextSize() {
return roundTextSize;
}
public void setRoundTextSize(float roundTextSize) {
this.roundTextSize = roundTextSize;
}
public int getRoundColor() {
return roundColor;
}
public void setRoundColor(int roundColor) {
this.roundColor = roundColor;
}
public int getRoundProgressColor() {
return roundProgressColor;
}
public void setRoundProgressColor(int roundProgressColor) {
this.roundProgressColor = roundProgressColor;
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
}
public float getTextSize() {
return textSize;
}
public void setTextSize(float textSize) {
this.textSize = textSize;
}
public float getRoundWidth1() {
return roundWidth1;
}
public void setRoundWidth1(float roundWidth) {
this.roundWidth1= roundWidth;
}
/*********************************控件属性(结束)************************************/
}</span>
二、xml中使用自定义控件
<com.grasp.nsuperseller.view.RoundProgressBar
android:id="@+id/roundProgressStat"
android:layout_width="170dip"
android:layout_height="170dip"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:background="@drawable/corner_common_yuan"
app:roundText="完成率"
app:roundTextSize="18sp"
app:textSize="28sp" />
二、xml中自定义圆形背景
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#f5f9f9"/>
<size android:width="50dp" android:height="50dp"/>
</shape>
三、attrs中配置自定义控件的属性值
<!-- 圆角进度条(开始)-->
<declare-styleable name="RoundProgressBar">
<attr name="roundColor" format="color"/>
<attr name="roundProgressColor" format="color"/>
<attr name="roundWidth1" format="dimension"/>
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
<attr name="roundText" format="string"/>
<attr name="roundTextColor" format="color"/>
<attr name="roundTextSize" format="dimension"/>
<attr name="max" format="integer"></attr>
<attr name="textIsDisplayable" format="boolean"></attr>
<attr name="style">
<enum name="STROKE" value="0"></enum>
<enum name="FILL" value="1"></enum>
</attr>
</declare-styleable>
<!-- 圆角进度条(结束)-->
四、在Activity中使用
备注 :100为最大的值,70为当前进度 ,可自己设置
50为速度,可以自己改变
public void companyMonthOnclick() {
progress = 0;
roundProgressStat.setProgress(0);
roundProgressStat.setMax(100);
new Thread(new Runnable() {
@Override
public void run() {
while (progress < 70) {
progress ++;
roundProgressStat.setProgress(progress);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}