A requirement was encountered in the project to display a circular progress bar and draw text in the center.
So how can the text be drawn at the center of the circle?
First come a picture (found online)
canvas.drawText(String text,float x,float y,Paint mTextPaint);
Parameter 1: text The text you want to draw
Parameter 2: The leftmost coordinate of the x text
Parameter 3: y BaseLine coordinate
Parameter 3: mTextPaint brush
So if you want to draw the text in the center of the text, you need to deal with it:
Suppose the diameter of the circle is circleWidth
1 The width is determined, that is, the X coordinate position is determined
There are two ways to get the width of the text:
@ A method getTextBounds (String text, int Start, End int, Rect bounds) Rect = RECT new new Rect () ; paint.setTextSize (rectF.width () * . 5 / 12 is ) ; // set the font size must be measured Before paint.setStrokeWidth( 3 ) ; paint.getTextBounds( full , 0 , full .length() , rect) ; //full is String is the "full" text to be drawn
// Method II the measureText a float (String text) paint.setTextSize (rectF.width () * . 5 / 12 is ) ; // set the font size must be measured before paint.setStrokeWidth ( . 3 ) ; a float textShowWidth = paint.measureText ( Full ) ;
But there are certain differences between the two methods:
getTextBounds
: It measures the display range of the text. For the image point, you place a variable rectangle outside this text, and then shrink the rectangle as much as possible, until the rectangle just tightly wraps the text, then the range of this rectangle is the bounds of this text
measureText()
: It measures the width occupied by the text when drawing. A text in the interface often needs to take up a little more width than its actual display width, so as to keep some space between the text and the text, and it will not appear too crowded. So it is larger than the measured width . measureText()
getTextBounds()
So we use the measureText() method to determine the X coordinate position of the drawn text:
X: circleWidth/2-textShowWidth/2
2 The height determination is the Y coordinate position determination
To align the center of the text with the center of the circle, you only need to move the Y coordinate from the center of the circle to the distance between the BaseLine line and the center line of the text.
Ascent: Distance from BaseLine to the top
Descent: BaseLine线到最底部的距离
Paint.FontMetrics fontMetrics = paint.getFontMetrics(); float descent = fontMetrics.descent;//descent是基于baseline下面,所以是正数 float ascent = fontMetrics.ascent;//ascent是基于baseline上面,所以是负数
所以
BaseLine线到文字中心线之间的距离:float dy = (descent - ascent) / 2 - descent;
Y坐标为: circleWidth / 2+ dy
总结: 在直径为circleWidth的圆中心位置绘制文本
canvas.drawText(text,circleWidth/2-textShowWidth/2,circleWidth/ 2+ dy,paint);
附:完整代码
xml布局文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.dyjf.drawview.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="300dp" android:background="#eeeeee" android:gravity="center"> <com.dyjf.drawview.ProgressView android:id="@+id/pv" android:layout_width="80dp" android:layout_height="150dp" android:layout_marginRight="160dp" android:background="#FFA07A" /> </LinearLayout> </LinearLayout>
View类
public class ProgressView extends View { private int width; private int height; private int circleWidth;//圆环直径 public ProgressView(Context context) { super(context); } public ProgressView(Context context, AttributeSet attrs) { super(context, attrs); } public ProgressView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //xml设置的宽度(80*3):80 是xml中80dp;3 是该手机设备的Density width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec);//xml设置的高度 circleWidth = width > height ? height : width;//根据xml文件取小的为圆直径 Log.i("ly", width + " - " + height); } String full = "满"; String buy = "抢"; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.parseColor("#cccccc")); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(circleWidth / 30); float strokeWidth = paint.getStrokeWidth(); //因为圆环有一定宽度所以预留出圆环宽度,所以从strokeWidth到circleWidth - strokeWidth RectF rectF = new RectF(strokeWidth, strokeWidth, circleWidth - strokeWidth, circleWidth - strokeWidth); canvas.drawArc(rectF, -90, 360, false, paint);//绘制底部灰色背景圆环 paint.setColor(Color.parseColor("#303F9F")); canvas.drawArc(rectF, -90, (float) (progress * 3.6), false, paint);//绘制蓝色进度条 paint.setTextSize(rectF.width() * 5 / 12);//根据圆环大小设置字体大小,可调整 paint.setStrokeWidth(3); paint.setStyle(Paint.Style.FILL); float textShowWidth = paint.measureText(full); Paint.FontMetrics fontMetrics = paint.getFontMetrics(); float dy = (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent; if (progress == 100) { paint.setColor(Color.parseColor("#cccccc")); canvas.drawText(full, circleWidth / 2 - textShowWidth / 2, circleWidth / 2 + dy, paint); } else { paint.setColor(Color.parseColor("#303F9F")); canvas.drawText(buy, circleWidth / 2 - textShowWidth / 2, circleWidth / 2 + dy, paint); } } float progress = 50; /** * 设置进度 * * @param pro */ public void changeProgress(float pro) { progress = pro; invalidate(); } }
效果图: