Android 模仿华为健康 自定义计步View

通过一个简单的自定义的View,模仿华为健康里面消耗热量和计步的圆弧View,来深入的理解RectF以及 canvas的drawArc方法。

华为健康的View是这样的:

Android 模仿华为健康 自定义计步View_第1张图片

最近写了一些自定义的view,其中用到RectF,Rect的地方比较多,于是有了这篇文章,来深入理解下RectF对象。先上效果图:

Android 模仿华为健康 自定义计步View_第2张图片

效果还是有点不太一样,但是别太在意那些细节了。。。

闲言少叙,分析下这个简单的View,可以看到是由两个圆弧和三段文字组成的,这两个圆弧,扫过的区域都是180度,两个圆弧之间需要留有间隙。
而要实现画一段圆弧,其实只需要两个步骤:

1:算出圆弧中线的一个矩形的方阵,这个地方就需要用到RectF了,为什么说是圆弧中线呢,因为圆弧是由宽度的,但是在绘制的时候,事实上是以圆弧最中间的那条线为基础画的,如果画360度的话,刚好是这个正方形的内切圆。

2:通过canvas的drawArc方法,就可以了。
这个oval 参数,就是我们 第一步得到的,圆弧的外切正方形,startAngle是开始的角度,需要注意的是,这个地方开始的0度是几何里面的180度,也就是中心点右边开始计数。

sweepAngle,就是圆弧横扫的角度,很明显,我们的view都是180度。

useCenter,是否包含中心点,我们这里明显不需要

paint 就是圆弧的画笔了

public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
throw new RuntimeException("Stub!");
}

分析完成之后,就开始动手操作了,

//默认开始角度
private int startAngle = 180;

//默认扫过的弧度
private int defaultSweepAngle = 180;

   //中心点坐标
    float centerX = getWidth() / 2;
    //热量外矩形区域
    RectF hotRectF = new RectF();
    float hotL = hotStrokeWidth / 2;
    float hotT = hotStrokeWidth / 2;
    float hotR = centerX * 2 - hotStrokeWidth / 2;
    float hotB = hotR;
    hotRectF.set(hotL, hotT, hotR, hotB);


//默认的灰色区域
  private void drawDefaultHotStroke(Canvas canvas, RectF f, float strokeWidth) {
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(defaultStrokeColor);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(strokeWidth);
    canvas.drawArc(f, startAngle, defaultSweepAngle, false, paint);
}
//当前进度的圆弧
private void drawProgressHotStroke(Canvas canvas, RectF f) {
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(hotStrokeProgressColor);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(hotStrokeWidth);
    canvas.drawArc(f, startAngle, currentHotLength, false, paint);
}

不知道大家有没有注意到计算外切正方形的时候,减去了画笔的宽度的一般,这一点就是上面提到的,绘制弧线的基准是以最中间那条线为准的,如果不减去的话,你会发现,圆弧的上下左右四个点会超出这个view之外。

绘制下面的圆弧的原理和这个一样,就不再赘述了,现在来分析下RectF

    RectF (float left, 
            float top, 
            float right, 
            float bottom)

这是RectF的构造函数,官网的解释是代表左上右下四个方向的坐标,但是其实这样解释并不准确,根据自己的实验,我们可以这样理解,前两个参数是矩阵左上角点的坐标,后两个是右下角点的坐标,这样,一个矩形就出来了。需要注意的是,要保证left <= right , top <= bottom.嗯,差不多,还是很好理解的。

那么 RectF 和 Rect 的区别是什么呢?
Rect的坐标点为int值,所以精度就没有RectF高了,RectF的构造函数可以直接把 RectF或者Rect传进去构建矩阵。其它的方法,都基本类似。

绘制文字的时候需要注意两个地方,文字的Y坐标,需要加上自身的高度的一半,避免出现覆盖的情况,这个地方使用了Paint的一个方法 getTextBounds 事实上把文字的属性都给 Rect 对象了,这样就可以拿到文字的所有想要的属性,而我们只需要传递文字内容和长度就可以了。

 private void drawText(Canvas canvas, float centerX) {
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(Color.BLACK);
    paint.setStyle(Paint.Style.STROKE);
    paint.setTextSize(stepTextSize);
    paint.setTextAlign(Paint.Align.CENTER);
    String textTop = "目标" + " " + targetStepNum;
    Rect textF = new Rect();
    paint.getTextBounds(textTop, 0, textTop.length(), textF);
    //文字高度
    stepTextHeight = textF.height();
    float textY = textF.height() / 2 + hotStrokeWidth / 2 + stepStrokeWidth + 2 * stokeOffset;
    canvas.drawText(textTop, centerX, textY, paint);
}

至此,这个简单的自定义View 已经写完了,之所以写这篇文章,是因为两点有猫腻的地方,一个是RectF的坐标点的定义,还有一个是canvas的drawArc 方法。现在只是个简单的view,并没有实现计步的功能。后续再完善。

源码传送门:
https://github.com/yangpin/ViewDemo

你可能感兴趣的:(Android 模仿华为健康 自定义计步View)