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中画文字有了更清晰的理解。如果仍有什么疑问,可以在文章下方留言。


相关文章
|
7月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
553 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
7月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
142 0
|
7月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
375 65
Android自定义view之网易云推荐歌单界面
|
7月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
713 84
|
7月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
226 3
|
缓存 Java Android开发
|
2月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
332 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
310 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
701 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
3月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
564 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡

热门文章

最新文章