Android自定义View之定点写文字

简介: Android自定义View之定点写文字

前言:有经验的Android开发者,应该都会遇到在自定义View的时候,在View的某个地方写文字,那么当你在自定义的View中写文字的时候,能够做到定点写文字吗?能够指哪写哪吗?写出来的文字的位置和自己想要的位置一样吗?即使你最后写的文字的位置和自己想象的位置是一样的,那么你知道其中的原理吗?如果其中有一个你不能回答出来,那就认真的阅读本文吧!本文会给出你想要的答案...

一个小例子

  看下下面的图,假如下面的图是我们要做出的效果

5c13baedb6f98475ef47a91ecb4eac5.png

很简单,有没有?就是在一个圆的中心写文字。红色的圆形很好画出来,那么我们怎么将文字写在圆的中心点上呢?第一时间想到的是拿到圆中心点的坐标,然后直接调用drawText()方法来写文字。实现的代码大致如下

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int measuredHeight = getMeasuredHeight();
        int measuredWidth = getMeasuredWidth();
        //cx,cy为圆的中心点的坐标
        int cx = measuredWidth / 2;
        int cy = measuredHeight / 2;
        canvas.drawCircle(cx, cy, mRadius, mPaint);
        mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
        mPaint.setColor(Color.WHITE);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.dp1));
        canvas.drawText("wizardev", cx, cy, mPaint);
    }

现在,看下上面代码实现的效果

b9b44ca74ca07598333f5d02665c358.png

上图中的黄线是在圆的中心点画的线,可以发现上面代码实现的效果,明显不是我们想要的效果,为什么会这样呢?下文会给出答案。

drawText()中的基线

  在Android中自定义View的时候,怎么让系统知道应该在哪里画出我们想要的图形呢?比如画上面的圆,这时我们就要告诉系统,我们要画的圆形的圆心在什么位置,告诉系统我们想要的圆的半径是多少,然后系统就能在合适的位置画出你想要的圆了。同样,在画文字的时候我们要指定文字在什么位置,而指定的坐标的位置就是文字的基线。

  要理解drawText()中的基线是什么,需要先了解一下darwText()方法,darwText()方法有四个参数,如下

drawText(@NonNull String text, float x, float y, @NonNull Paint paint)

第一个参数为你想要写的内容,第二个参数为文字开始的X轴坐标,第三个参数为文字开始的Y轴坐标,第四个参数为画笔。以第二个第三个参数画的一条水平线,就是drawText()的基线。如上文中的第二张图,黄色的线即为drawText()基线,

注:第二和第三个参数不一定为文字开始的坐标,也可能为文字中心的坐标或则文字结尾的坐标,具体是哪种坐标与Paint中的setTextAlign()方法有关。

  可以得出结论,只要确定了基线的位置就确定了要画的文字的位置了。那么给定一个坐标,怎么确定基线的位置呢?其实画文字的时候,除了基线以外,还有其他几条线,其他几条线的位置如下图

f56795b2a12f6eebe90136729c21d5c.png

这几条线的意义分别是:

  • ascent: 系统建议的,字符所占的最高高度所在线
  • descent:系统建议的,字符所占的最低高度所在线
  • top: 可绘制的最高高度所在线
  • bottom: 可绘制的最低高度所在线

这几条线的位置可以通过FontMetrics对象获得。

FontMetrics

(1)FontMetrics概述

  描述给定文本的各种度量值的类,它有五个成员变量,分别为topascentdescentbottomleading。这几个成员变量的值都是相对基线位置的距离,如:

FontMetrics.top = top的Y坐标 - 基线

(2)获取FontMetrics对象

想要获取FontMetrics,可以通过getFontMetrics()方法获取,具体代码如下

Paint mPaint = new Paint()
mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
mPaint.setColor(Color.WHITE);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setStrokeWidth(1);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();

(3)FontMetrics注意事项

  使用FontMetrics获取到的topascentdescentbottomleading成员变量的值,是相对于基线的距离,并不是坐标,可以看下下图,方便理解

d3ab5f114487e9a567785b2a6e8a932.png

可以发现topascent的值为负数,descentbottom的值为正数,为什么会这样呢?因为top线和ascent线在基线的上方,FontMetrics对象中的几个成员变量的值都是表示相对基线的位置。

指定位置写文字

  了解了FontMetrics再结合下图

99ce30778c441be4eef34a0f4260976.png

可以得到下面的公式:

  • top的Y坐标 = 基线 + fontMetrics.top
  • ascent的Y坐标 = 基线 + fontMetrics.ascent
  • decent的Y坐标 = 基线 + fontMetrics.descent
  • bottom的Y坐标 = 基线 + fontMetrics.bottom

(1)给定左上方点写字

33b74532499927c1a8fe01d40527dbb.png

根据得出的公式可以计算出基线的Y坐标

top的Y坐标 = 基线 + fontMetrics.top

基线 = top的Y坐标 -  fontMetrics.top

实现的代码如下

Paint mPaint = new Paint();
mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
mPaint.setStrokeWidth(1);
mPaint.setColor(Color.RED);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float baseLine = cy-fontMetrics.top;//cy指定点的Y坐标
canvas.drawText("wizardev", 0, baseLine, mPaint);

(2)给定中间线写文字

75b74d1a94d9f10317f183dbf49a62c.png

给定中间线写文字,可以说是自定义view写文字时用的最多的了,如,将文字写在圆的正中间,如上图,圆的中心线将文字平分,这种就是本文说的给定中间线写文字。文章前面说了,只要确定了基线的位置,文字的位置也就确定了,那么像这种,怎样来确定基线的位置呢?这时我们可以借助其他的几条线来计算出基线的位置。

e5e05fb1d00b60f912c7217501b5e68.png

如上图,将topcenter之间的间距设为A,将centerbaseline之间的距离设为B,将centerbottom之间的距离设为C。这是就可以得出下面的公式

A = C = (bottom - top)/2
B = baseline - center
B = C - (bottom - baseline )

然后根据上文得到的公式:

bottom = fontMetrics.bottom + baseline
top  = fontMetrics.top + baseline

可以将最上面的公式修改为:

baseline - center = (fontMetrics.bottom + baseline - fontMetrics.top - baseline) / 2 - (fontMetrics.bottom + baseline - baseline)

最后的到的公式为:

baseline = center - (fontMetrics.bottom - fontMetrics.top) / 2 + fontMetrics.bottom

上面的到的公式就是给出中心线的位置,最后计算出的基线所在位置的公式。

(3)给定底部线线文字

  这种情况应该是最简单的了,直接把给定点的Y坐标作为基线的Y坐标就行了。

结束语

  文章到这里,已经回答了文章开始的几个问题,相信阅读本文之后,你也对自定义View中画文字有了更清晰的理解。如果仍有什么疑问,可以在文章下方留言。


相关文章
|
30天前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
61 0
|
5天前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
6天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
19 5
|
14天前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
14天前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
21 2
|
15天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
18天前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
19 2
|
30天前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
Android开发