自定义View入门 —— 制作圆圈进度条

这里写图片描述

今天说下怎么自定义一个简单的进度条=。=

自定义View首要确定两个东西,第一个就是 View 的大小第二个就是绘图位置!!剩下的就是画笔啥的,这方面的就没有什么好讲的了。。。

确定view的大小

首先,确定View 的大小,和自定义ViewGroup一样,重写onMeasure() 方法来测量:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = 0;
        int height = 0;
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY){
            width = MeasureSpec.getSize(widthMeasureSpec);
        }
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY){
            height = MeasureSpec.getSize(heightMeasureSpec);
        }
        //如果边长有预设值,则取最长的边组成正方形,否则用半径*2 + padding作为边长
        if ( width > height ){
            height = width;
        }else if ( width < height){
            width = height;
        }else if ( width == 0 && height == 0){
            width = circleR *2;
            height = circleR * 2;
        }
        setMeasuredDimension(width + padding, height + padding);
    }

其中还是要优先使用布局中给好的尺寸,先得到长宽的模式啥的。(在这篇自定义ViewGroup里面已经讲过了:http://blog.csdn.net/ocwvar/article/details/50682213
由于咱们的是圆形,所以咱们要统一长宽为一样的尺寸来组合成正方形。
如果布局中没有规定尺寸,咱们就使用圆圈的半径+padding来确定View的大小。上面代码已经写得很清楚了。

确定画布大小位置

由于View的绘制是在一张 Canvas上面 的,所以咱们 使用RectF 来定位绘图位置。

方法generateCircelPosition()

private void generateCircelPosition(){
        reDrawCircle = false; //需要重绘标记归位
        float cLeft,cRight,cTop,cBottom;
        cLeft = ( getMeasuredWidth() - 2*circleR ) / 2;
        cRight = ( cLeft + 2*circleR );
        cTop = ( getMeasuredHeight() - 2*circleR ) / 2;
        cBottom = ( cTop + 2*circleR );
        circlePosition = new RectF( cLeft , cTop , cRight , cBottom );
    }

咱们要让圆圈居中显示,而且咱们在确定View大小的时候已经让其成为了正方形,所以咱们的坐标为:

  • 左坐标:( View总长 - 直径 ) / 2
  • 右坐标:左坐标 + 直径
  • 顶坐标:( View总高 - 直径 ) / 2
  • 底坐标:顶坐标 + 直径

新建文字画笔

创建方法
initPaintText()

private void initPaintText(){
        if (paintText == null || reDrawText){
            reDrawText = false; //重绘文字标记归位
            paintText = new Paint();
            if (textColor == 0){
                paintText.setColor(Color.DKGRAY);
            }else {
                paintText.setColor(textColor);
            }
            paintText.setAntiAlias(true);
            paintText.setTextSize(textSize);
            paintText.setTextAlign(Paint.Align.CENTER);
            Paint.FontMetricsInt fontMetrics = paintText.getFontMetricsInt();
            textBaseLine = (circlePosition.bottom + circlePosition.top - fontMetrics.bottom - fontMetrics.top) / 2;
        }
    }

咱们先介绍这些画笔的属性

  • setColor 设置画笔颜色
  • setAntiAlias 是否使用反锯齿
  • setTextSize 顾名思义,文字大小
  • setTextAlign 文字居中 ( 特指文字从中开始出现,与文字整体坐标无关 )

关于文字坐标垂直居中
也就是最下面两行代码,来确定文字的垂直位置。
我这里参考了这篇文章:http://blog.csdn.net/hursing/article/details/18703599

新建圆圈画笔

创建方法
initPaintCircle()

private void initPaintCircle(){
        if (paintcircle == null || reDrawProgressBar){
            reDrawProgressBar = false; //重绘标记归位
            paintcircle = new Paint();
            paintcircle.setAntiAlias(true);
            paintcircle.setColor(progressBarColor);
            paintcircle.setStyle(Paint.Style.STROKE);
            paintcircle.setStrokeWidth(5f);
        }
    }
  • setStyle 设定画笔风格 ( 这里我们设置成 空心 )
  • setStrokeWidth 设定画笔厚度

绘制图像onDraw()

这个方法是自定义View中几乎都要重写的方法 ( 除非你的View不需要显示东西…… )

onDraw(Canvas canvas)

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (circlePosition == null || reDrawCircle){
            generateCircelPosition(); //首次绘制或需要重绘。计算绘制画布位置
        }
        if (showCircle){
            initPaintCircle();
            canvas.drawArc(circlePosition, -90, (progress * (360f / max)), false, paintcircle);
        }
        if (showText){
            initPaintText();
            if (!TextUtils.isEmpty(text)){
                canvas.drawText(text,circlePosition.centerX(),textBaseLine,paintText);
            }else {
                canvas.drawText(Integer.toString(progress)+"%",circlePosition.centerX(),textBaseLine,paintText);
            }
        }
    }

这里要好好解释下canvas.drawArc、canvas.drawText

canvas.drawArc(circlePosition, -90, (progress * (360f / max)), false, paintcircle);

drawArc绘制扇形

  • 参数1:绘图位置。这里就是咱们确定下来的画布绘制位置。
  • 参数2:起始绘制角度。12点位置是 -90° 所以咱们从这里开始绘制
  • 参数3:结束绘制角度。咱们根据进度 progress 来确定占多少份360°
  • 参数4:是否绘制到圆心的线。上面动态图中的是不使用的,下面有个使用的样式图。
  • 参数4:绘制画笔。咱们用之前做好的画笔 paintcircle

绘制到圆心的线后:
这里写图片描述

canvas.drawText(Integer.toString(progress)+"%",circlePosition.centerX(),textBaseLine,paintText);

drawText绘制文字

  • 参数1:绘制的文字。
  • 参数2:绘制X坐标。这里使用绘制区域的中间
  • 参数3:绘制Y坐标。这里使用计算好的垂直居中的坐标
  • 参数4:绘制画笔。使用之前做好的画笔 paintText

请求更新图像

这里用更新进度方法来做例子
创建方法
setProgress(int progress)

public void setProgress(int progress){
        this.progress = progress;
        ViewCompat.postInvalidateOnAnimation(this);
    }

这里使用 ViewCompat.postInvalidateOnAnimation(this); 来请求更新图像。就不需要用原来的那个 invalidate() 来更新了,毕竟这个不是异步更新的。

完毕

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值