自定义控件 《进度条,统计圆环图》从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(); }