圆形进度条

        这个栏目写一些自定义控件相关的思想,对于基础知识,如画图、动画、事件分发等不会做深入探讨,我只去做一些实战使用,下方会给出一些好的文章链接供大家参考使用。这篇是第一篇关于自定义控件的文章,先写个简单的压压惊。事实上自定义控件没那么难,只是大家想的太难,太过于恐惧了,自定义控件我们就看做是我们在设计一个控件,我们在根据现有的资源(指android的现有控件)进行拓展和延伸。很多情况下我们都会继承已有的view去实现我们想要的效果,也可以使用多个控件进行组合使用。自定义控件范围很大,几篇文章说不完,我只能说希望带大家入个门,解决一些你的恐惧心理。当你的思想已经具备了,你再看看画图、动画、事件分发、view绘制原理等等,你就不会感到这个很难了,今天我们先拿圆形进度条来说说事。

先上个图:


        如上图,我们需要完成这个控件的绘制应该如何做到呢?我们需要画一个圆环,需要画一个弧度。中间需要直接写两行文字,这样就能完成了。这里自定义属性我只对文字和进度进行设置,其他的不去做,如果有需要可以自己去添加。自定义属性代码和初始化如图:

<declare-styleable name="CirclePlan">
    <attr name="planCount" format="float"></attr>
    <attr name="planText" format="string"></attr>
</declare-styleable>

TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CirclePlan);
//文字
planText=array.getString(R.styleable.CirclePlan_planText);
//进度
planCount=array.getFloat(R.styleable.CirclePlan_planCount,10);

这里自定义属性我就不做过多解释了,大家可以参考 此链接,这里清晰的解释了format的是个属性值。


下面我们直接看onDraw方法我们解释这个方法下如何画这个进度条

@Override
    protected void onDraw(Canvas canvas) {
//        Bitmap bitmap= Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
//        canvas=new Canvas(bitmap);
        width=getWidth();
        height=getHeight();
        radius=height/3;
        RectF oval=new RectF(width/2-radius,height/2-radius,width/2+radius,height/2+radius);
        Path path=new Path();
        path.addArc(oval,0,360);
        canvas.drawPath(path,paint_d);
        Path path1=new Path();
        path1.addArc(oval,-90,planCount*3.6f);
        canvas.drawPath(path1,paint_b);
        //此处应是planCount+"%"
        canvas.drawText(planCount+"%",width/2,height/2+fm.descent-(fm.descent-fm.ascent)/2,paint_t);
//        paint_t.setColor(context.getResources().getColor(R.color.black));
//        paint_t.setTextSize(35);
        //此处应是planText
        canvas.drawText(planText,width/2,height/2-fm.descent+(fm.descent-fm.ascent),paint_t);
    }
        代码就这么多,开始的两行可以看自己需求,这个可以帮助你把你所画的图形全部放进bitmap里面,事实上我们推荐这么做的,因为你需要设置背景的时候就需要这个bitmap,当然我们不需要,所以我就把它注释了,这里用来展示一下给大家看一下如何使用。

        这里我们获取了控件的宽高,事实上这个控件就是我们目前所在的类,所以可以直接getWidth就能获取到控件的宽度,自定义view是不需要measure和layout,对自己测量和设置是没有任何意义的,在自定义ViewGroup时measure也并不一定是必须的,但是layout是必须的。我们必须设置子控件的位置才行,但不需要测量,因为可以覆盖ViewGroup。

下面我们进入正题,我们写了一个RectF后面用了path路径,这里我们为什么不用drawCircle呢,不是说好了用这个的么,那是因为我们后续还会用到这个的嘛,而且他可以保证不会说你使用drawCircle再使用drawArc那个进度就跑的看不见了,我经常就遇到这个情况,所以干脆就使用这一个RectF,至少他肯定不会变。我们只需要对设置0-360度即可画一个圆,后面我们在根据planCount进度数去画一个弧度,这样就能完成了进度。

下面我们看drawText方法,这个fm可能大家不知道是干嘛的。很多情况下我们在画文本的时候,上下不能居中,那是因为画文字的时候总是有个空白的地方,比方说textview他的文字不会贴到控件边上,总是会有一点距离,paint画文字的时候也是这样,距离上面的叫做ascent,距离下面的叫做descent。我们看下图,这个图是我拷过来的,也感谢这位朋友提供的图片,我就直接拿过来用了,这个我们看到这有个上边距和下边距,除了我们上面讲到的,还有个base。我们画文字的时候需要怎么做呢。我们已经有了圆心坐标,基本可以定在height/2左右,我们应当还要向上移动半个文字的高度,而文字高度就等于ascent+descent,那么我们可以拿到这个值除以2再用height/2减去这个值就是我们画文字的位置了。因为我画了两行,所以我的位置不是这个,大家可以自行考虑自己文字的位置。关于FontMetrics可以参考此链接。到此基本讲完了,末尾附上全部代码及使用方式。



全部代码:

package xiancdm.boneng.com.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import xiancdm.boneng.com.xian_cdm.R;

/**
 * 自定义圆形进度条
 * Created by Administrator on 2016/9/13.
 */
public class CirclePlan extends View {
    private String planText;
    private float planCount;
    private Context context;
    private int width,height;
    private int radius;
    private Paint.FontMetrics fm;
    private Paint paint_b,paint_d,paint_t;
    public CirclePlan(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CirclePlan);
        //文字
        planText=array.getString(R.styleable.CirclePlan_planText);
        //进度
        planCount=array.getFloat(R.styleable.CirclePlan_planCount,10);
        initPaint();
    }
    public void initPaint(){
        //进度画笔
        paint_b=new Paint();
        paint_b.setColor(context.getResources().getColor(R.color.cirle_plan_proceed));
        paint_b.setStyle(Paint.Style.STROKE);
        paint_b.setStrokeWidth(10);
        paint_b.setAntiAlias(true);
        //圆形画笔
        paint_d=new Paint();
        paint_d.setColor(context.getResources().getColor(R.color.cirle_plan_max));
        paint_d.setStyle(Paint.Style.STROKE);
        paint_d.setStrokeWidth(10);
        paint_d.setAntiAlias(true);
        //文字画笔
        paint_t=new Paint();
        paint_t.setColor(context.getResources().getColor(R.color.black));
        paint_t.setAntiAlias(true);
        paint_t.setTextAlign(Paint.Align.CENTER);
        paint_t.setTextSize(35);
        //计算文字大小,用于文字居中
        fm=paint_t.getFontMetrics();
    }
    @Override
    protected void onDraw(Canvas canvas) {
//        Bitmap bitmap= Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
//        canvas=new Canvas(bitmap);
        width=getWidth();
        height=getHeight();
        radius=height/3;
        RectF oval=new RectF(width/2-radius,height/2-radius,width/2+radius,height/2+radius);
        Path path=new Path();
        path.addArc(oval,0,360);
        canvas.drawPath(path,paint_d);
        Path path1=new Path();
        path1.addArc(oval,-90,planCount*3.6f);
        canvas.drawPath(path1,paint_b);
        //此处应是planCount+"%"
        canvas.drawText(planCount+"%",width/2,height/2+fm.descent-(fm.descent-fm.ascent)/2,paint_t);
//        paint_t.setColor(context.getResources().getColor(R.color.black));
//        paint_t.setTextSize(35);
        //此处应是planText
        canvas.drawText(planText,width/2,height/2-fm.descent+(fm.descent-fm.ascent),paint_t);
//        canvas.drawText(planText,width/2,height/2-(fm.ascent+fm.descent)/2,paint_t);
    }

    public String getPlanText() {
        return planText;
    }

    public void setPlanText(String planText) {
        this.planText = planText;
    }

    public float getPlanCount() {
        return planCount;
    }

    public void setPlanCount(float planCount) {
        this.planCount = planCount;
        postInvalidate();
    }
}

使用方式:

<xxx.xxx.xxx.xxx.CirclePlan
     android:id="@+id/cp_ThatDay"
     android:layout_width="0dp"
     android:layout_weight="1"
     android:layout_height="match_parent" />



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值