完成一个进度条的定义

自定义view是Android进阶高级的关键,这个过程也是比较艰难。学习了很久的自定义,今天按照网络上已有的思路,把进度条完成的感触做一记录。

1.定义几个属性

在资源文件夹写:

<declare-styleable name="StepView">
        <attr name="outerColor" format="color"></attr>
        <attr name="innerColor" format="color"></attr>
        <attr name="borderWidth" format="dimension"></attr>
        <attr name="stepTextSize" format="dimension"></attr>
        <attr name="stepTextColor" format="color"></attr>
    </declare-styleable>

2.创建一个类

创建一个类,继承View 开始重写构造方法。写出需要的变量,在构造方法中获取将来属性中传递的值。

获取的属性对应的全局变量:

/**
     * 外层圆弧颜色
     */
    private int mOuterColor;

    /**
     * 内层圆弧颜色
     */
    private int mInnerColor;

    /**
     * 字体大小
     */
    private int mTextSize;

    /**
     * 字体颜色
     */
    private int mTextColor;

    /**
     * 圆弧宽度
     */
    private int mBorderWidth;

    /**
     * 默认5
     */
    private int borderWidth  = 5;

构造方法获取属性值:

 public MyStepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.StepView);
        mOuterColor = a.getColor(R.styleable.StepView_outerColor,OUTER_COLOR);
        mInnerColor = a.getColor(R.styleable.StepView_innerColor,INNER_COLOR);
        mTextColor = a.getColor(R.styleable.StepView_stepTextColor,TEXT_COLOR);
        mBorderWidth = a.getDimensionPixelSize(R.styleable.StepView_borderWidth,borderWidth);
        mTextSize = a.getDimensionPixelSize(R.styleable.StepView_stepTextSize,mTextSize);
        a.recycle();}
这里需要注意:容易忘记写a.recycle();

重写onMeasure测量大小

获取View的参数,重新测量View的大小。这里的进度条按照一个正方形来处理,因此我们获取View的宽和高,取一个小的值设置为正方形的宽和高,这里可以不处理Mode。

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取mode
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取宽和高
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(widthMeasureSpec);
        //确保是一个正方形,不一样大取小值
        setMeasuredDimension(width>height?height:width,width>height?height:width);
    }


重写onDraw()方法,绘制View

这个计步器进度条的关键就是绘制了。我们先在创建一个Pain对象并且设置获取的属性,我们把初始化的过程放在构造方法中进行。在构造方法中添加代码初始化一个Pain。

  mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setStrokeCap( Paint.Cap.ROUND);//设置圆角
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(mOuterColor);
我们在绘制的时候修改不同圆的属性。设置不同颜色

这里需要注意的一个设置圆弧两端的样式,默认的两端是没有圆角的方形:

 mPaint.setStrokeCap( Paint.Cap.ROUND);//设置圆角

同时创建一个绘制文字的Paint:

mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setColor(mTextColor);
创建好Paint后就是计算要绘制的参数了,画图分析下绘制的参数。




我们绘制的图形为上图蓝色圆除去红色90度角以外的地方。就是紫色线的角度,X轴正向为0°,顺时针到开始的位置是135°的位置。结束的位置是右下红色线的位置,所以,135°开始,需要绘制扫过270°的区域。

canvas.drawArc(rect,135,270,false,mPaint);//起始位置角度135,扫描划过270度

这个绘制的方法第二,第三个参数就是这个样子。第一个参数是一个RectF对象。对于内部的圆弧,我们需要设置动态的值。定义两个变量mStepMax和mCurrentStep,然后计算当前mCurrentStep值占总数的比乘以270°。

 float raudius = (float) mCurrentStep/mStepMax;
        canvas.drawArc(rect,135,270*raudius,false,mPaint);

绘制文字,绘制文字需要计算文字的大小和baseline。

String mStepText = mCurrentStep+"";
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(mStepText,0,mStepText.length(),textBounds);//获取字体大小
baseline 的计算方式可以查看其它有关baseline的计算过程,这里直接使用:
 Paint.FontMetricsInt metricsInt = mTextPaint.getFontMetricsInt();//获取基线
        int dy = (metricsInt.bottom-metricsInt.top )/2-metricsInt.bottom;//获取dy ,FontMetricsInt的top是一个负数,bottom 是一个正数 
        int baseline = getHeight()/2+dy;//计算基线
计算绘制文字的开始位置(View的中心,减去文字的一半的位置就是绘制文字的开始位置):

int dx = getWidth()/2-textBounds.width()/2;
所以onDraw方法就是:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画图形
        //1.画外圆,圆弧闭合了,left,right设置0,边缘被裁剪,描边有宽度,需要减去,减去变的宽
        RectF rect = new RectF(0,0,getWidth(),getHeight());//创建一个区域
        mPaint.setColor(mOuterColor);//重新设置颜色
        canvas.drawArc(rect,135,270,false,mPaint);//起始位置角度135,扫描划过270度
        //2.画内圆
        if(mStepMax==0){//防止除数为0
            return;
        }
        float raudius = (float) mCurrentStep/mStepMax;
        mPaint.setColor(mInnerColor);//重新设置颜色
        canvas.drawArc(rect,135,270*raudius,false,mPaint);
        //3画文字
        String mStepText = mCurrentStep+"";
        Rect textBounds = new Rect();
        mTextPaint.getTextBounds(mStepText,0,mStepText.length(),textBounds);//获取字体大小
        Paint.FontMetricsInt metricsInt = mTextPaint.getFontMetricsInt();//获取基线
        int dy = (metricsInt.bottom-metricsInt.top )/2-metricsInt.bottom;//获取dy
        int baseline = getHeight()/2+dy;//计算基线
        int dx = getWidth()/2-textBounds.width()/2;
        canvas.drawText(mStepText,dx,baseline,mTextPaint);
    }
添加总数4000一个默认300绘制的结果:



可以发现左,上,右的边有一部分被截掉了,观察,差不多就是圆弧宽的一半。因此,我们在设置绘制圆弧的区域RectF大小的时候,不要从0开始到View的宽高,留出圆弧borderwidth 的一半的距离。

RectF rect = new RectF(mBorderWidth/2,mBorderWidth/2,getWidth()-mBorderWidth/2,getHeight()-mBorderWidth/2);
现在查看结果如图:



最后,为了代码中使用,设置两个set方法来修改属性mCurrentStep和mStepMax。同时添加上synchronized 关键字,保证多线程下正常使用。

  /**
     * 设置最大步数
     * @param mStepMax
     */
    public synchronized void setStepMax(int mtepMax) {
        this.mStepMax = mStepMax;
    }

    /**
     * 设置当前步数
     * @param mCurrentStep
     */
    public synchronized void setCurrentStep(int currentStep) {
        this.mCurrentStep = mCurrentStep;
        invalidate();//不断绘制
    }

具体使用,我们可以在Activity中设置最大值使用Handler发送延时消息,调用View的setCurrentStep()方法实现。 

参考文章:http://www.jianshu.com/p/4e0eb9bb09ab

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值