支付宝芝麻信用页面自定义View的简单制作(续)

前两个月刚刚写了一篇关于支付宝芝麻信用页面自定义View的总结,感觉写的不太好,链接如下:
http://blog.csdn.net/anny_lin/article/details/49474555

当时写的时候没有考虑到布局的问题,当移动View的时候,view就出现绘图错乱了,还好有个哥们看了给我提醒了一下,最近刚好比较闲,就寻思重新记录一下写自定义View的过程,算是对自定义View的一个小的总结吧,顺便把遇到过的坑记录一下,提醒一下自己。


注意:这篇文章针对http://blog.csdn.net/anny_lin/article/details/49474555
出现的布局问题作修改,其他实现参考上面链接


废话不多说,首先看看,人家支付宝芝麻信用的页面吧:

支付宝芝麻信用页面自定义View的简单制作(续)_第1张图片

上图展示的就是一个支付宝信用的一个页面,我们从页面的构造开始分析:
最上面的视图我们并不需要自定义,直接使用textView即可,主要需要自定义的模块就只有中间那一部分,我们把它单独拿出来分析一下:
我们可以看到它是由两个半圆环,即外面的半圈圈构成,思考一下,在使用

canvas.drawArc(rectF,165, 210,false,outArcPaint);

这个api就可以搞定了,我们还能发现在第二个圆圈里面有刻度线着写小东东,同样视图最内层还有刻度线的说明,这个我们需要怎么做呢?思考一下,我们可以通过不断地旋转画布定点绘制,当画布旋转完成我们刻度线和刻度线下方的字体就可以完成啦。
接下来就是要写中间的字了,调用

 canvas.drawText(numString,centerX-textWidth/2,centerY,textPaint);

即可,还是很容易的,我们的静态效果到这就分析完成了,我们看看代码的实现方式:
重写的onMeasure()方法:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int wrap_Len = DensityUtil.dip2px(context, 300);
        int width = measureDimension(wrap_Len, widthMeasureSpec);
        int height = measureDimension(wrap_Len, heightMeasureSpec);
        len=Math.min(width,height);
        //保证他是一个正方形
        setMeasuredDimension(len,len);

    }
    public int measureDimension(int defaultSize, int measureSpec){
        int result;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if(specMode == MeasureSpec.EXACTLY){
            result = specSize;
        }else{
            result = defaultSize;   //UNSPECIFIED
            if(specMode == MeasureSpec.AT_MOST){
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

我们这里保证这个View是一个正方形的效果,防止视图太难看。

初始化工具类:

private void init() {
        //两外圈的距离
        distance_from_two_acr=DensityUtil.dip2px(context,14);
        //外圈画笔
        outArcPaint=new Paint();
        outArcPaint.setAntiAlias(true);
        outArcPaint.setStrokeWidth(8);
        outArcPaint.setColor(Color.parseColor("#ffee44"));
        outArcPaint.setStyle(Paint.Style.STROKE);
        //内圈画笔
        inArcPaint=new Paint();
        inArcPaint.setAntiAlias(true);
        inArcPaint.setStrokeWidth(30);
        inArcPaint.setColor(Color.parseColor("#ffffff"));
        inArcPaint.setAlpha(120);
        inArcPaint.setStyle(Paint.Style.STROKE);

        //正中间字体画笔
        textPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(60);
        textPaint.setColor(Color.parseColor("#ffffff"));

    }

上述初始化了一些画笔工具以及一些变量,这里就不详细的去说明paint各个方法的含义了,不懂得同学请度娘。

重点来了:

最重要的方法就是我们的onDraw()方法了,所有的自定义View一般都要重写此方法进行视图的绘制:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获得中心点坐标
        int centerX= len/2;
        int centerY= len/2;
        Log.e("the center is","centerX="+centerX+"    centerY"+centerY);
        //只要传入相对的坐标即可,画最最外圈的圆环
        RectF rectF=new RectF(0+DEFAULT_PADDING,0+DEFAULT_PADDING
                ,getMeasuredWidth()-DEFAULT_PADDING,getMeasuredHeight()-DEFAULT_PADDING);
        canvas.drawArc(rectF,165, 210,false,outArcPaint);
        //内圆环画圈
        rectF=new RectF(0+DEFAULT_PADDING+distance_from_two_acr,0+DEFAULT_PADDING+distance_from_two_acr,getMeasuredWidth()-DEFAULT_PADDING-distance_from_two_acr
                ,getMeasuredHeight()-DEFAULT_PADDING-distance_from_two_acr);
        canvas.drawArc(rectF,165, 210,false,inArcPaint);
        //中间字体的绘制
        drawText(canvas,centerX,centerY);
        //进行内圆环刻度线的draw
        drawtheLine(canvas,centerX,centerY);

    }
 private void drawtheLine(Canvas canvas,int centerX,int centerY) {
        canvas.save();
        //我们将画布旋转,实际上是旋转我们的坐标轴
        canvas.rotate(-105,getMeasuredWidth()/2,getMeasuredHeight()/2);
        int lineStartY= (int) (DEFAULT_PADDING+distance_from_two_acr-inArcPaint.getStrokeWidth()/2-1);
        int lineEndY= (int) (lineStartY+inArcPaint.getStrokeWidth());
        //每次画布旋转的角度
        int rotateRadius=210/10;
        for(int i=1;i<12;i++){

            if (i%2==0){
                canvas.drawLine(centerX, lineStartY, centerX, lineEndY, keduDarkPaint);
            }else {
                canvas.drawLine(centerX, lineStartY, centerX, lineEndY, keduLightPaint);

            }
            float textLength=keduFontPaint.measureText(stringArray[i-1]);
            canvas.drawText(stringArray[i-1],centerX-textLength/2,lineEndY+30,keduFontPaint);
            canvas.rotate(rotateRadius,centerX,centerY);
        }
        canvas.restore();

    }

    private void drawText(Canvas canvas,int centerX,int centerY){
        if (!TextUtils.isEmpty(textString)){
            //计算字体的长度
            float textWidth=textPaint.measureText(textString);
            //textPaint.descent()-textPaint.ascent()测量字体高度
            canvas.drawText(textString,centerX-textWidth/2,centerY+10+(textPaint.descent()-textPaint.ascent()),textPaint);
        }
        if (!TextUtils.isEmpty(textString)){
            float textWidth=textPaint.measureText(numString);
            canvas.drawText(numString,centerX-textWidth/2,centerY,textPaint);
        }
    }

最麻烦的无非是坐标的计算,这里就不详细的讲了,要讲可能要将一大堆,所以就不详述了,这里讲几个需要注意的地方:


1.当我们使用一些canvas方法的时候,我们需要知道方法中的坐标都是相对于本身View而言的,一般而言,我们并不需要考虑使用getX()或者getY()来进行坐标的计算的,否则当我们改变布局的位置的时候,是会引起坐标的错位问题的,这个很重要!

2.当考虑到旋转画布的问题的时候,坐标的计算方面会比较抽象,可能花的时间会很多,需要深入了解canvas.rotate()的工作原理,这一方面我自己也有点晕忽忽的,网上很多人讲的都不一样,有时间的时候需要多加研究一下。


我们静态的页面到这里算是完成了,我们看一下效果图:
支付宝芝麻信用页面自定义View的简单制作(续)_第2张图片
支付宝芝麻信用页面自定义View的简单制作(续)_第3张图片

我们可以看到修改了布局后,自定的View效果保持一致,这正是我们所需要的,好的,接下来我们就需要让图动起来了,我们分别需要一个类似于progreeBar的圆环动态效果,一个背景渐变效果,这里不考虑数字变化的动态效果,网上好像有着方面的控件,自己实现可能有一定的难度,所以我们考虑progreeBar的圆环动态效果和背景渐变效果实现:
1.圆环动态效果,我们可以通过view.post方法进行重绘的操作
2.背景渐变,属性动画中提供了这个api,我们也可以实现

由于这篇文章已经实现过了,这里就不叙述了,这篇文章主要解决布局错乱的问题
代码:

//背景渐变动画实现
        ValueAnimator coloranim= ObjectAnimator.ofInt(context, "backgroundColor", 0xFFFF8080, 0xFF8080FF);
        coloranim.setDuration(30 * 180);
        coloranim.setEvaluator(new ArgbEvaluator());
        coloranim.start();

更新条的实现:

post(new Runnable() {
            @Override
            public void run() {
                if (start20/7);

                    postInvalidateDelayed(10);

                }

            }
        });

最后的效果:

支付宝芝麻信用页面自定义View的简单制作(续)_第4张图片

上述的Demo下载地址:

https://github.com/JerryChan123/android-learning/tree/master

你可能感兴趣的:(android之自定义view)