Android 模仿華為健康 自定義計步View

通過一個簡單的自定義的View,模仿華為健康里面消耗熱量和計步的圓弧View,來深入的理解RectF以及 canvas的drawArc方法。

華為健康的View是這樣的:

最近寫了一些自定義的view,其中用到RectF,Rect的地方比較多,于是有了這篇文章,來深入理解下RectF對象。先上效果圖:

效果還是有點不太一樣,但是別太在意那些細節(jié)了。。。

閑言少敘,分析下這個簡單的View,可以看到是由兩個圓弧和三段文字組成的,這兩個圓弧,掃過的區(qū)域都是180度,兩個圓弧之間需要留有間隙。
而要實現(xiàn)畫一段圓弧,其實只需要兩個步驟:

1:算出圓弧中線的一個矩形的方陣,這個地方就需要用到RectF了,為什么說是圓弧中線呢,因為圓弧是由寬度的,但是在繪制的時候,事實上是以圓弧最中間的那條線為基礎畫的,如果畫360度的話,剛好是這個正方形的內切圓。

2:通過canvas的drawArc方法,就可以了。
這個oval 參數(shù),就是我們 第一步得到的,圓弧的外切正方形,startAngle是開始的角度,需要注意的是,這個地方開始的0度是幾何里面的180度,也就是中心點右邊開始計數(shù)。

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;
    //熱量外矩形區(qū)域
    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);


//默認的灰色區(qū)域
  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);
}

不知道大家有沒有注意到計算外切正方形的時候,減去了畫筆的寬度的一般,這一點就是上面提到的,繪制弧線的基準是以最中間那條線為準的,如果不減去的話,你會發(fā)現(xiàn),圓弧的上下左右四個點會超出這個view之外。

繪制下面的圓弧的原理和這個一樣,就不再贅述了,現(xiàn)在來分析下RectF

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

這是RectF的構造函數(shù),官網的解釋是代表左上右下四個方向的坐標,但是其實這樣解釋并不準確,根據自己的實驗,我們可以這樣理解,前兩個參數(shù)是矩陣左上角點的坐標,后兩個是右下角點的坐標,這樣,一個矩形就出來了。需要注意的是,要保證left <= right , top <= bottom.嗯,差不多,還是很好理解的。

那么 RectF 和 Rect 的區(qū)別是什么呢?
Rect的坐標點為int值,所以精度就沒有RectF高了,RectF的構造函數(shù)可以直接把 RectF或者Rect傳進去構建矩陣。其它的方法,都基本類似。

繪制文字的時候需要注意兩個地方,文字的Y坐標,需要加上自身的高度的一半,避免出現(xiàn)覆蓋的情況,這個地方使用了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 方法?,F(xiàn)在只是個簡單的view,并沒有實現(xiàn)計步的功能。后續(xù)再完善。

源碼傳送門:
https://github.com/yangpin/ViewDemo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容