自定义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的主要内容,如果未能解决你的问题,请参考以下文章

如何给progressbar圆形进度条设置颜色

Android开发怎么自定义绘制如下图中这种进度条?急需!在线等!

Delphi里ProgressBar在更新进度的时候,能够显现百分比吗?

progressbar怎么显示复制进度

Android自定义控件实现带百分比显示进度条,可自定义颜色

自定义控件:绘制圆环的实现过程