如何将自定义文本TextView绘制在其他图形中心位置

项目中遇到一个需求要求展示一个圆形进度条并在中心绘制文字。


所以怎么才能把文字绘制在圆形的最中心呢?

先来一张图(网上找的)


canvas.drawText(String text,float x,float y,Paint mTextPaint);

参数1:text  想要绘制的文本

参数2:x  文本最左边坐标

参数3:y  BaseLine所在坐标

参数3:mTextPaint  画笔

所以想要将文本绘制在文本最中心需要处理一下:

假设圆的直径为circleWidth

1 宽度确定 即X坐标位置确定

获取文本的宽度有两种方式:

//方法一 getTextBounds(String text, int start, int end, Rect bounds)
Rect rect = new Rect();
paint.setTextSize(rectF.width() * 5 / 12);//设置字体大小一定要在测量之前
paint.setStrokeWidth(3);
paint.getTextBounds(full, 0, full.length(), rect);//full为String是要绘制的"满"字文本
//方法二 float measureText(String text)
paint.setTextSize(rectF.width() * 5 / 12);//设置字体大小一定要在测量之前
paint.setStrokeWidth(3);
float textShowWidth = paint.measureText(full);

但两种方法有一定区别:

getTextBounds: 它测量的是文字的显示范围。形象点来说,你这段文字外放置一个可变的矩形,然后把矩形尽可能地缩小,一直小到这个矩形恰好紧紧包裹住文字,那么这个矩形的范围,就是这段文字的 bounds

measureText(): 它测量的是文字绘制时所占用的宽度。一个文字在界面中,往往需要占用比他的实际显示宽度更多一点的宽度,以此来让文字和文字之间保留一些间距,不会显得过于拥挤。所以 measureText() 比 getTextBounds() 测量出的宽度要大一些

所以我们选用measureText()方法来确定绘制文本X坐标位置:

X: circleWidth/2-textShowWidth/2

 2 高度确定 即Y坐标位置确定


想要绘制出文字的中心和圆的中心对齐只需要只需要将Y坐标从圆的中心往下移动BaseLine线到文字中心线之间的距离即可。

Ascent:  BaseLine线到最顶部的距离

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();
    }
}

效果图:


猜你喜欢

转载自blog.csdn.net/u011288271/article/details/79802099