前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义View之带进度百分比ProgressBar

自定义View之带进度百分比ProgressBar

作者头像
fanfan
发布2022-05-07 14:58:09
6050
发布2022-05-07 14:58:09
举报
文章被收录于专栏:编程思想之路编程思想之路

先上几张自定义所实现的效果图吧,有兴趣的可以继续往下看

实现思路,前四张图呢在自定义progressbar时没有加入text文本,文本是在xml布局时加上去的,最后一张是与progressbar定义在一起的。可以看到有以下几种情况

1,图1自定义中未集成文本的圆环显示,这样的话需要自己添加文本,做法也很简单

利用相对布局,将文本与progressbar进行嵌套,如下:这是整个页面的布局文件,所自定的view为RoundProgressBar

代码语言:javascript
复制
<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>

然后在代码中进行处理:当点击确定百分比发生变化后改变文本内容

代码语言:javascript
复制
 mProgress.setCurrentProgress(Integer.valueOf(mEdit.getText().toString()));
                mTv.setText("已完成" + "\n" + mProgress.getPercent() + "%");

这种实现方法有一个好处是文本实现起来相对随意,不用画笔实现

2,像图2这种有填充有圆环的自己感觉用户体验不是太好,不如图4

这种做法忽略掉圆心,做法也很简单,那就是在画圆时useCenter传入一个false,

代码语言:javascript
复制
                    <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,可以对画笔对象进行一些设置,比如

代码语言:javascript
复制
paint.setStyle(Paint.Style.STROKE);//设置为空心

代码语言:javascript
复制
paint.setStyle(Paint.Style.FILL);//设置为实心,在画时有填充

好了,大致分析了一下几种情况的不同,接下来看如何自定义View

要想实现这种自定义的view先分析都需要什么,(直接将图5考虑进来,如果不需要显示可以直接注掉)

  • 首先是画整个圆环(圆环颜色,画笔对象,圆环宽度)
  • 按百分比进行画弧(圆弧颜色,最大值,当前值)
  • 考虑是空心还是实心(style)
  • 画出文本(文本颜色,文本大小,文本是否显示)
  • 画时考虑坐标

仔细想想,这个View所要画的也就这些东西了,

自定义view分以下几步

继承View(不要怪我啰嗦,说不定真有人会忘....)

代码语言:javascript
复制
public class RoundProgressBar extends View 

既然我们已经知道需要哪些量,那就先进行构造

代码语言:javascript
复制
 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方法

构造方法

代码语言:javascript
复制
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文件夹下创建一个资源文件,在该文件中定义了所需字段的默认值

代码语言:javascript
复制
<?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方法

代码语言:javascript
复制
  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

在onDraw方法中进行画view

首先要画圆环

代码语言:javascript
复制
        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属性起作用,必须在画圆时对半径进行修改,

代码语言:javascript
复制
 int padding =  Math.min(getPaddingLeft(),getPaddingTop());
        int radius = (int)(center - ringWidth/2 - padding);

圆环画好后可以开始画圆弧了

代码语言:javascript
复制
        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; } 

圆弧画好后可以开始写文本了,文本的话应该简单的多了

代码语言:javascript
复制
       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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义百分比的progressbar
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档