在上一篇文章《Android神笔之Paint》学习了Paint的基本用法,但是具体的应用我们还没有实践过。从标题中可知,本文是带领读者使用Paint,自定义一个进度条控件。

上图就是本文要实现的效果图。既然是自定义控件,本文的该控件是直接继承View,然后重写View的onMeasure和onDraw方法来实现。其中onMeasure主要作用是测量控件的宽/高。而onDraw则是将界面绘制到屏幕上。

从效果的效果上看,我们需要自定义一些属性,如:进度度条的颜色、圆边框的颜色、圆边框的宽度和文本的大小等等。

具体的自定义属性请看下面attrs.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="CustomProgressBar"><attr name="roundProgressColor" format="color"></attr><attr name="roundColor" format="color"></attr><attr name="roundWidth" format="dimension"></attr><attr name="textSize" format="dimension"></attr><attr name="textColor" format="color"></attr><attr name="max" format="integer"></attr><attr name="textShow" format="boolean"></attr><attr name="style"><enum name="STROKE" value="0"></enum><enum name="FILL" value="1"></enum></attr></declare-styleable>
</resources>
复制代码

接下来看本文的最重要部分,也就是自定义View

public class CustomProgressBar extends View {private int max = 100;//总进度private int roundColor = Color.RED;//进度圆弧的颜色private float roundWidth = 10;//圆边框宽度private int roundProgressColor = Color.BLUE;//默认的大圆环边框颜色private float textSize = 55;//文本大小private int textColor = Color.GREEN;//文本默认颜色private boolean textShow = true;//是否展示文本public static final int STROKE = 0;//描边public static final int FILL = 1;//填充private int style = STROKE;//默认描边private int progress;//进度private Paint mPaint;private int mWidth = 200;//默认控件宽度,wrap_content时候使用private int mHeight = 200;//默认控件高度,wrap_content时候使用public CustomProgressBar(Context context) {this(context, null);}public CustomProgressBar(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init(context, attrs);}private void init(Context context, AttributeSet attrs) {mPaint = new Paint();if (attrs != null) {TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar);max = typedArray.getInteger(R.styleable.CustomProgressBar_max, 100);roundColor = typedArray.getColor(R.styleable.CustomProgressBar_roundColor, Color.BLUE);roundProgressColor = typedArray.getColor(R.styleable.CustomProgressBar_roundProgressColor, Color.BLUE);textColor = typedArray.getColor(R.styleable.CustomProgressBar_textColor, Color.GREEN);textSize = typedArray.getDimension(R.styleable.CustomProgressBar_textSize, 55);roundWidth = typedArray.getDimension(R.styleable.CustomProgressBar_roundWidth, 10);textShow = typedArray.getBoolean(R.styleable.CustomProgressBar_textShow, true);style = typedArray.getInt(R.styleable.CustomProgressBar_style, 0);typedArray.recycle();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(mWidth,mHeight);}else if (widthSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(mWidth,heightSpecSize);}else if (heightSpecMode == MeasureSpec.AT_MOST){setMeasuredDimension(widthSpecSize,mHeight);}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);final int paddingLeft = getPaddingLeft();final int paddingRight = getPaddingRight();final int paddingTop = getPaddingTop();final int paddingBottom = getPaddingBottom();int width = getWidth() - paddingLeft - paddingRight;int height = getHeight() - paddingBottom - paddingTop;//画默认的大圆环float radius = (float)Math.min(width,height)/2.0f;//中心坐标点mPaint.setColor(roundColor);mPaint.setStyle(Paint.Style.STROKE);//描边mPaint.setStrokeWidth(roundWidth);//圆环边的宽度
//        if (style == STROKE){
//            mPaint.setStrokeWidth(roundWidth);//圆环边的宽度
//        }mPaint.setAntiAlias(true);//(float cx, float cy, float radius, @NonNull Paint paint)canvas.drawCircle(paddingLeft+width/2,paddingTop+height/2,radius,mPaint);//画进度百分比mPaint.setColor(textColor);mPaint.setStrokeWidth(0);//圆环的宽度mPaint.setTextSize(textSize);mPaint.setTypeface(Typeface.DEFAULT_BOLD);int percent = (int)(progress/(float)max * 100);if(textShow && percent!=0 && style == STROKE){//(@NonNull String text, float x, float y, @NonNull Paint paint)canvas.drawText(percent+"%", (getWidth()-mPaint.measureText(percent+"%"))/2f,//y公式: float baselineY = centerY + (fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottomgetWidth()/2f-(mPaint.descent()+mPaint.ascent())/2f,mPaint);}//画圆弧//矩形区域,定义圆弧的形状大小//(float left, float top, float right, float bottom)RectF oval = new RectF(paddingLeft, paddingTop, width+paddingLeft, height+paddingTop);mPaint.setColor(roundProgressColor);mPaint.setStrokeWidth(roundWidth);//圆环边的宽度switch (style){case STROKE:mPaint.setStyle(Paint.Style.STROKE);//(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,@NonNull Paint paint)//useCenter:设置圆弧在绘画的时候,是否经过圆形canvas.drawArc(oval , 0, 360*progress/max, false, mPaint);break;case FILL:mPaint.setStyle(Paint.Style.FILL_AND_STROKE);if(progress!=0)canvas.drawArc(oval , 0, 360*progress/max, true, mPaint);break;default:break;}}public void setProgressWidth(int width) {mWidth = width;}public void setProgressHeight(int height) {mHeight = height;}public synchronized void setMax(int max) {if (max < 0) {throw new IllegalArgumentException("max不能小于0");}this.max = max;}public void setRoundColor(int roundColor) {this.roundColor = roundColor;}public void setRoundWidth(float roundWidth) {this.roundWidth = roundWidth;}public void setRoundProgressColor(int roundProgressColor) {this.roundProgressColor = roundProgressColor;}public void setTextSize(float textSize) {this.textSize = textSize;}public void setTextColor(int textColor) {this.textColor = textColor;}public void setTextShow(boolean textShow) {this.textShow = textShow;}public synchronized void setProgress(int progress) {if (progress < 0) {throw new IllegalArgumentException("progress不能小于0");}if (progress > max) {progress = max;}if (progress <= max) {this.progress = progress;postInvalidate();}}public synchronized int getMax() {return max;}public int getRoundColor() {return roundColor;}public float getRoundWidth() {return roundWidth;}public int getRoundProgressColor() {return roundProgressColor;}public int getTextColor() {return textColor;}public boolean isTextShow() {return textShow;}public synchronized int getProgress() {return progress;}
}
复制代码

流程:初始化的时候会拿到自定义属性,然后onMeasure方法中测量控件的宽和高,该方法主要处理了LayoutParams的wrap_content,当wrap_content时,默认设置默认宽/高,而不是让控件占据整个屏幕,需要调用setMeasuredDimension方法测量。最后测量得到了控件的宽/高,调用onDraw方法将界面绘制到屏幕上,在onDraw方法绘制的时需要考虑padding的情况,如果不做padding处理,则padding将不起作用。

onDraw绘制流程:先绘制一个默认的大圆环,然后在圆中心绘制百分比的文本,最后再绘制一个进度圆环,进度圆环会覆盖底部的默认大圆环,这样就达到显示进度的情况。

设置好画笔之后,使用canvas.drawCircle绘制默认的大圆环,再次设置画笔,使用canvas.drawText方法绘制文本;画圆弧时需要定义一个矩形区域RectF,通过canvas.drawArc方法绘制。

绘制好之后,如何让用户看到进度条在变化呢?其实就是通过setProgress方法里面的postInvalidate()方法,该方法会刷新界面,刷新界面时会调用onDraw,这样就可以将进度画到屏幕上,进度条不停的在变化。

使用

XML中使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.main.paint.PaintActivity"><com.main.paint.CustomProgressBarandroid:id="@+id/progressbar"android:layout_width="200dp"android:layout_height="200dp"app:roundProgressColor="#FF0000"app:roundWidth="2dp"app:textColor="#FF0000"app:style="STROKE"android:padding="30dp"app:textSize="20dp"/><com.main.paint.CustomProgressBarandroid:id="@+id/progressbar01"android:layout_width="200dp"android:layout_height="200dp"app:roundProgressColor="#FF0000"app:roundWidth="2dp"app:textColor="#FF0000"app:style="FILL"android:padding="30dp"app:textSize="20dp"/></LinearLayout>
复制代码

Activity代码如下:

public class PaintActivity extends AppCompatActivity {private CustomProgressBar mCustomProgressBar;private CustomProgressBar mCustomProgressBar01;private int progress;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_paint);mCustomProgressBar = (CustomProgressBar)this.findViewById(R.id.progressbar);mCustomProgressBar.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {progress = 0;while (progress <= 100) {progress += 2;mCustomProgressBar.setProgress(progress);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}});mCustomProgressBar01 = (CustomProgressBar)this.findViewById(R.id.progressbar01);mCustomProgressBar01.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {progress = 0;while (progress <= 100) {progress += 2;mCustomProgressBar01.setProgress(progress);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}});}
}
复制代码

这样就完成了一个自定义的进度条控件,并且在onDraw方法中使用Paint将界面绘制出来。读者可以自行实践一把,加深对Paint的理解。

Android Paint应用之自定义View实现进度条控件相关推荐

  1. android lrc 歌词view,自定义View强势来袭,用自定义View实现歌词显示控件下篇之自定义LyricView的实现...

    在上篇中,我与大家分享了关于如何进行*.lrc歌词文件的解析,以及将解析完成后的歌词展示在镶嵌在ScrollView中的TextView上,就这样而言,一个简单的歌词显示功能也就实现了. 但是,如何才 ...

  2. Kotlin 自定义View之实现标尺控件(选择身高、体重等)

    本篇文章讲的是Kotlin 自定义view之实现标尺控件Ruler,以选择身高.体重等.开发中,当我们需要获取用户的身高和体重等信息时,如果直接让他们输入,显然体验不够好.像类似于唯品会.好轻等APP ...

  3. Android中进度条控件使用

    android中进度条控件使用 ProgressBar pb = findViewById(R.id.pb);pb.setMax(100);pb.setProgress(33); 转载于:https: ...

  4. ExtJs4 笔记(8) Ext.slider 滚轴控件、 Ext.ProgressBar 进度条控件、 Ext.Editor 编辑控件...

    本篇要登场的有三个控件,分别是滚轴控件.进度条控件和编辑控件. 一.滚轴控件 Ext.slider 1.滚轴控件的定义 下面我们定义三个具有代表意义滚轴控件,分别展示滚轴横向.纵向,以及单值.多值选择 ...

  5. [转载]ExtJs4 笔记(8) Ext.slider 滚轴控件、 Ext.ProgressBar 进度条控件、 Ext.Editor 编辑控件...

    作者:李盼(Lipan) 出处:[Lipan] (http://www.cnblogs.com/lipan/) 版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其 ...

  6. [K/3Cloud]进度条控件编程接口

    进度条控件编程接口 1.启动进度查询 this.GetControl<ProgressBar>().Start(2)  //每2秒查询一次进度 2.汇报进度 在插件中重载 OnQueryP ...

  7. MFC中进度条控件的使用方法

    进度条控件是程序开发中基础控件之一,常用于显示程序的进度.在进行程序安装.文件传输时经常用到.其用法也比较简单固定. 转自:http://jingyan.baidu.com/article/95c9d ...

  8. DevExpress的进度条控件ProgressBarControl的使用-以ZedGraph添加曲线进度为例

    场景 Winform控件-DevExpress18下载安装注册以及在VS中使用: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/1 ...

  9. 使用GDI+实现圆形进度条控件的平滑效果

    DownLoad Src 传统的GDI绘制图形时的一个致命缺点是图像存在锯齿毛糙, 使用GDI+能绘制漂亮的渐变图像并有光滑图像的功能.利用GDI+对圆形进度条控件进行修改,效果如下:

最新文章

  1. Postgresql在Windows下的解压安装
  2. Python运维自动化psutil 模块详解(超级详细)
  3. JQuery 匿名函数初识(转载)
  4. Spring boot定制错误数据携带出去
  5. mysql got signal 6_UTC - mysqld got signal 6
  6. java uuid 生成方法
  7. Codeforces 982 C. Cut 'em all!(dfs)
  8. 电容的q值计算公式_在设计电路中电容容量大小、耐压等级选取详解 (转)
  9. Ubuntu更换国内源(apt更换源)
  10. 软件测试 学习之路 DOS常用命令
  11. 2021年Java大厂面试必备面试题
  12. webstorm 高效开发 (html)
  13. 使用ASP.NET Atlas ItemView控件显示集合中的单个数据
  14. matlab中数组的创建
  15. TSU-求最大最小数
  16. ai如何做倒角和圆角_在ai中怎么用小白工具把矩形的直角改成圆角?,你值得一看的技巧...
  17. Android SOS功能模块开发
  18. 既生AtomicXXX,何生LongAdder?
  19. [教程]通过注册表关闭win10 xbox dvr 游戏录像
  20. powerpc 和arm的寄存器都相同吗

热门文章

  1. 字典生成_Python数据字典生成工具详解
  2. python函数分几种_简单了解Python中的几种函数
  3. mx3 android 5.1,魅族MX3揭晓:猎户座处理器5.1寸屏幕
  4. HDLBits 系列(17) 计数器的级联实现1000分频的分频器
  5. 【Verilog HDL 训练】第 03 天
  6. Nand Flash,Nor Flash,BPI Flash,SPI Flash 的区别?
  7. 在Windows2016中回到DOS时代用tt练习打字
  8. Visual Studio 2013 在使用 razor无智能提示的解决办法
  9. SQUAD的rnet复现踩坑记
  10. jQuery基础知识准备