自定义View之带进度百分比ProgressBar
Posted fanfan-公众号-码农修仙儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View之带进度百分比ProgressBar相关的知识,希望对你有一定的参考价值。
先上几张自定义所实现的效果图吧,有兴趣的可以继续往下看
实现思路,前四张图呢在自定义progressbar时没有加入text文本,文本是在xml布局时加上去的,最后一张是与progressbar定义在一起的。可以看到有以下几种情况
1,图1自定义中未集成文本的圆环显示,这样的话需要自己添加文本,做法也很简单
利用相对布局,将文本与progressbar进行嵌套,如下:这是整个页面的布局文件,所自定的view为RoundProgressBar
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"/>
<com.fang.zrf.wifidemo.widget.RoundProgressBar
android:id="@+id/progress"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerInParent="true" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定"
android:layout_alignRight="@+id/input"
android:layout_marginTop="20dp"/>
<EditText
android:id="@+id/input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/input_current_progress"
android:padding="10dp"
android:layout_marginTop="20dp"/>
</RelativeLayout>
</RelativeLayout>
然后在代码中进行处理:当点击确定百分比发生变化后改变文本内容
mProgress.setCurrentProgress(Integer.valueOf(mEdit.getText().toString()));
mTv.setText("已完成" + "\\n" + mProgress.getPercent() + "%");
这种实现方法有一个好处是文本实现起来相对随意,不用画笔实现
2,像图2这种有填充有圆环的自己感觉用户体验不是太好,不如图4
这种做法忽略掉圆心,做法也很简单,那就是在画圆时useCenter传入一个false,
<pre name="code" class="java"> /**
*@param oval The bounds of oval used to define the shape and size
* of the arc
* @param startAngle Starting angle (in degrees) where the arc begins
* @param sweepAngle Sweep angle (in degrees) measured clockwise,,你要画的百分比的弧度,
*如果传入为true,则画圆时就会包括圆心,其实就相当于用的圆规,如果设置为true,则画百分比时圆规一脚固定在圆心
*另一脚沿着圆弧按百分比进行画弧
* @param useCenter <span style="color:#3333FF;">If true, include the center of the oval in the arc, and
close it if it is being stroked. This will draw a wedge</span>
* @param paint The paint used to draw the arc
*/
canvas.drawArc(rectF,0,360*currentProgress/maxProgress,false,paint);
3,有了图2的分析就可以知道,图3和图4传入的useCenter参数为true。
除了包不包含圆心之分,还有一个区分那就是图1和图3是空心无填充,图2和图4是实心有填充,这个是怎么设计的呢?
可以看到在画圆时传入了一个画笔的对象paint,可以对画笔对象进行一些设置,比如
paint.setStyle(Paint.Style.STROKE);//设置为空心
和
paint.setStyle(Paint.Style.FILL);//设置为实心,在画时有填充
好了,大致分析了一下几种情况的不同,接下来看如何自定义View
要想实现这种自定义的view先分析都需要什么,(直接将图5考虑进来,如果不需要显示可以直接注掉)
- 首先是画整个圆环(圆环颜色,画笔对象,圆环宽度)
- 按百分比进行画弧(圆弧颜色,最大值,当前值)
- 考虑是空心还是实心(style)
- 画出文本(文本颜色,文本大小,文本是否显示)
- 画时考虑坐标
仔细想想,这个View所要画的也就这些东西了,
自定义view分以下几步
继承View(不要怪我啰嗦,说不定真有人会忘....)
public class RoundProgressBar extends View
既然我们已经知道需要哪些量,那就先进行构造
private Paint paint;//画笔对象
private int ringColor;//圆环color
private int ringProgressColor;//进度弧度color
private int textColor;//百分比字体color
private float textSize;//百分比字体size
private float ringWidth;//圆环宽度
private int maxProgress;//进度最大值
private int currentProgress;//当前进度
private boolean textIsDisplay;//是否显示中间进度百分比
private int styleRes;//进度风格
然后创建字段的setter和getter方法
构造方法
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 typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
//获取自定义属性和默认值
ringColor = typedArray.getColor(R.styleable.RoundProgressBar_ringColor, Color.BLACK);
ringProgressColor = typedArray.getColor(R.styleable.RoundProgressBar_ringProgressColor,Color.RED);
textColor = typedArray.getColor(R.styleable.RoundProgressBar_textColor,Color.BLUE);
textSize = typedArray.getDimension(R.styleable.RoundProgressBar_textSize,14);
textIsDisplay = typedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplay,true);
styleRes = typedArray.getInt(R.styleable.RoundProgressBar_style,1);
typedArray.recycle();
}
在这里用到了一个自定义的风格RoundProgressBar的style
在values文件夹下创建一个资源文件,在该文件中定义了所需字段的默认值
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RoundProgressBar">
<attr name="ringColor" format="color"/>
<attr name="ringProgressColor" format="color"/>
<attr name="textColor" format="color"/>
<attr name="textSize" format="dimension"/>
<attr name="ringWidth" format="dimension"/>
<attr name="maxProgress" format="integer"/>
<attr name="textIsDisplay" format="boolean"/>
<attr name="style" >
<enum name="STROKE" value="0"/>
<enum name="FILL" value="1"/>
</attr>
</declare-styleable>
</resources>
好了初始化已经完成,接下来就是拿起画笔开始画了
覆写view的onDraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
在onDraw方法中进行画view
首先要画圆环
int center = getWidth()/2; //获取到自定义控件的宽度,当然这是你在xml文件中定义的
int radius = (int)(center - ringWidth/2);//内圆半径
paint.setColor(ringColor);//设置圆环颜色
paint.setStyle(Paint.Style.STROKE);设置是否填充
paint.setStrokeWidth(ringWidth);//设置圆环宽度
paint.setAntiAlias(true);//设置是否平滑
canvas.drawCircle(center,center,radius,paint);画圆
学过数学的都应该知道吧要想画圆两个要素就行,一个是圆心坐标,一个就是圆半径
附上一张说明图帮助大家理解
当然像这种画圆方法,你在xml文件中使用该自定义的控件时用padding属性是没用的,因为在画圆时,原点坐标是view的左上角,圆心坐标是(x轴到圆点的距离,y轴到圆点的距离),要想对控件设置padding属性起作用,必须在画圆时对半径进行修改,
int padding = Math.min(getPaddingLeft(),getPaddingTop());
int radius = (int)(center - ringWidth/2 - padding);
圆环画好后可以开始画圆弧了
paint.setStrokeWidth(ringWidth);//圆弧宽度
paint.setColor(ringProgressColor);//圆弧颜色
//坐标,left,top,right,bottom,参考说明图,很好理解
RectF rectF = new RectF(center - radius,center - radius,center + radius,center + radius);
switch (styleRes){
//这两种情况一个是空心一个是实心
case STROKE:
paint.setStyle(Paint.Style.STROKE);
//计算出圆弧的长度 = 360 * 当前进度/最大值,至于所传参数是false还是true的介绍上文已经说明
canvas.drawArc(rectF,0,360*currentProgress/maxProgress,true,paint);
// canvas.drawArc(rectF,0,360*currentProgress/maxProgress,false,paint);
break;
case FILL:
paint.setStyle(Paint.Style.FILL);
if (currentProgress != 0){
//canvas.drawArc(rectF,0,360*currentProgress/maxProgress,false,paint);
<pre name="code" class="java"> canvas.drawArc(rectF,0,360*currentProgress/maxProgress,false,paint);
} break; }
圆弧画好后可以开始写文本了,文本的话应该简单的多了
paint.setStrokeWidth(0);
paint.setColor(textColor);//文本颜色
paint.setTextSize(textSize);//文本字体大小
paint.setTypeface(Typeface.DEFAULT_BOLD);//typeface
percent = (int)(((float)currentProgress/(float) maxProgress)*100);//计算 百分比
float textWidth = paint.measureText( percent + "%");//测量文本的宽度
Paint.FontMetrics textHeigh = paint.getFontMetrics();//为了使文本居中,我们要根据文本的宽高来获取坐标
float height = (float)Math.ceil(textHeigh.descent - textHeigh.top);//获取到文本的高度
if (textIsDisplay && percent != 0 && styleRes == STROKE){//如果是空心圆且百分比不为0,且设置的为显示,则显示
//横坐标为center-textWidth/2 :外圆环的半径减去文本的宽度,
//纵坐标为center+height/2:外圆环的半径 加上文本的高度
canvas.drawText(percent + "%",center - textWidth/2 ,center + height/2 ,paint);
}
至此,一个带进度百分比的progress已经自定义完成
现在想想,曾经面试有人问自定义view要实现哪些方法,不就是构造方法和ondraw么。。
附上demo下载地址
自定义百分比的progressbar
以上是关于自定义View之带进度百分比ProgressBar的主要内容,如果未能解决你的问题,请参考以下文章
Android开发怎么自定义绘制如下图中这种进度条?急需!在线等!
Delphi里ProgressBar在更新进度的时候,能够显现百分比吗?