一.先上圖

image.png
二.功能拆分
1.背景圓
2.進(jìn)度圓(進(jìn)度開頭是弧形的)
3.中間的文字(圓圈內(nèi)的水平&豎直居中)
三.細(xì)節(jié)
1.背景圓沒什么難度,進(jìn)度圓的開頭和結(jié)尾都是圓的,用到了paint的api為: progressCirclePaint.setStrokeCap(Paint.Cap.ROUND);
2.文字的繪制,主要就是居中效果,水平居中設(shè)置 textPaint.setTextAlign(Paint.Align.CENTER)即可,豎直方向上可以有2種思路,一個是根據(jù)TextBounds的top&bottom 來計算豎直的偏移量,第二個是使用FontMetrics的ascent&descent來計算偏移量(具體可參考rengwuxian關(guān)于文字的繪制),兩者效果區(qū)別不大,自由選擇,倒是顯示效果需要根據(jù)文字是靜態(tài)的還是動態(tài)的來稍微調(diào)整偏移量的計算,因?yàn)閯討B(tài)文字可能會出現(xiàn)跳動
四.欠缺
進(jìn)度條沒有動畫
五.關(guān)于文字的左邊距
如果文字字體過大,文字的左邊距也可能過大,如下圖
image.png
如需要取消這個邊距,同樣也可用TextBounds調(diào)整,調(diào)整后:
image.png
六.talk is cheap
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathDashPathEffect;
import android.graphics.PathMeasure;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
/**
* 體重表
* 圓環(huán)&中間的信息
* 重點(diǎn)是中間的信息string居中
* TODO 需要將設(shè)置進(jìn)度以及設(shè)置中間文字信息的api暴露出來
* TODO 提供兩種文字豎直方向居中的算法
*/
public class WeightBoard extends View {
private static final float RADIUS_CIRCLE = Utils.dp2px(150);
private static final int START_ANGLE = -90;
Paint bgCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint progressCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
private float width, height;
private RectF rectF;
private String text = "60Kg";
final Rect textBounds = new Rect();
private Paint.FontMetrics fontMetrics;
public WeightBoard(Context context) {
this(context, null);
}
public WeightBoard(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public WeightBoard(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
float circleStrokeWidth = Utils.dp2px(15);
bgCirclePaint.setColor(Color.GRAY);
bgCirclePaint.setStyle(Paint.Style.STROKE);
bgCirclePaint.setStrokeWidth(circleStrokeWidth);
progressCirclePaint.setStrokeCap(Paint.Cap.ROUND);
progressCirclePaint.setColor(Color.parseColor("#CC9966"));
progressCirclePaint.setStyle(Paint.Style.STROKE);
progressCirclePaint.setStrokeWidth(circleStrokeWidth);
textPaint.setColor(Color.parseColor("#0094ff"));
textPaint.setTextSize(Utils.dp2px(40));
textPaint.setFakeBoldText(true);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setTextAlign(Paint.Align.CENTER);
rectF = new RectF();
fontMetrics = textPaint.getFontMetrics();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = getWidth();
height = getHeight();
rectF.set(((float) (width / 2)) - RADIUS_CIRCLE, ((float) (height / 2)) - RADIUS_CIRCLE, ((float) (width / 2)) + RADIUS_CIRCLE, ((float) (height / 2)) + RADIUS_CIRCLE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1先畫兩個重疊的圓環(huán)
//1.1先畫背景圓
canvas.drawCircle(width / 2, height / 2, RADIUS_CIRCLE, bgCirclePaint);
//1.2畫進(jìn)度圓弧,注意圓弧的開頭是圓潤的
canvas.drawArc(rectF, START_ANGLE, 120, false, progressCirclePaint);
//2.畫中間的信息文字
//2.1根據(jù)FontMetrics來調(diào)整豎直偏移
float verticalOffset = (fontMetrics.ascent + fontMetrics.descent) / 2;
//2.2使用TextBounds來計算偏移
// textPaint.getTextBounds(text, 0, text.length(), textBounds);
// verticalOffset = (textBounds.bottom + textBounds.top)/ 2;
canvas.drawText(text, width / 2, height / 2 - verticalOffset, textPaint);
bgCirclePaint.setStrokeWidth(Utils.dp2px(1));
canvas.drawLine(width / 2, height / 2, width / 2 + 100, height / 2, bgCirclePaint);
testClipLeftSpace(canvas);
}
private void testClipLeftSpace(Canvas canvas) {
textPaint.setTextAlign(Paint.Align.LEFT);
textPaint.setTextSize(Utils.dp2px(200));
textPaint.getTextBounds("a",0,"a".length(),textBounds);
canvas.drawText("a", -textBounds.left, 500, textPaint);
textPaint.setTextSize(Utils.dp2px(20));
canvas.drawText("a", 0, 500 + textPaint.getFontSpacing(), textPaint);
}
}
引用:
HenCoder Android 開發(fā)進(jìn)階:自定義 View 1-3 drawText() 文字的繪制

