Android自定义View之文字居中

简介: 前言本文讲文字的居中,不过在你阅读本文之前,强烈建议你读一下我的上一篇文章Android自定义View之DashBoard(仪表盘) ,因为上一篇的内容讲了Paint和Canvas等基础绘制的知识,你学会上一篇的内容再看现在的这篇会容易的多。

前言

本文讲文字的居中,不过在你阅读本文之前,强烈建议你读一下我的上一篇文章Android自定义View之DashBoard(仪表盘) ,因为上一篇的内容讲了Paint和Canvas等基础绘制的知识,你学会上一篇的内容再看现在的这篇会容易的多。看了文章题目,你会发现本文只讲一个点,就是文字居中,可能你会觉得就一个文字居中有必要单独拿一篇文章来讲吗?一开始我自己觉得没必要,后来发现有很多工作3、4年的Android开发者都没弄明白到底该怎么使文字居中,所以就有了这篇文章。关于文字居中,我保证你认真看了我的这篇文章,你一定能彻彻底底地明白如何去做。

文字居中

我们先来回忆一下绘制文字的方法:
drawText(String text, float x, float y, Paint paint)
方法的参数很简单: text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:

img_cacf3f764599d0ba5e7a578eb0c24d3a.png
坐标的位置

注意要特别强调一下y(也就是纵坐标)是 基线的位置,这时候你一定会问啥事基线,长什么样啊,接着看图
img_8ef70ecfbcddd5f10bdef8862b775535.png

为什么会要用基线?这是因为每个字符的长度不太一样,比如我图中的例子,“a"、“b”和“g”这三个字符的长度明显不一样,我们没有办法简单的顶部对齐或者底部对齐,所以我们需要这么一个东西来让文字的重心对齐,这样会给用户一个更好的视觉效果。知道了文字绘制基线的概念,那么如果我们在(0,0)位置(原点)绘制一下"abcdefg"会怎么样呢?

img_0468b2ca1625bd5be6932fcc313cbee0.png

放心,你没有看错,因为我刚才说了y坐标指的是文字基线的位置,基线的位置在“0”坐标,那么绘制的东西自然是在坐标系以外也就是我们看不见的地方了。
只有明白了基线的概念,我们才能继续讲如何居中。
关于文字居中,其实水平方向居中,非常简单,只需要一行代码

mPaint.setTextAlign(Paint.Align.CENTER);//Paint设置水平居中

下面我们先不管竖直居中的问题,先在(getWidth()/2,getHeight()/2)View的中心点,绘制一下文字

img_fde6fe8387d2078afc7c7e819679b28e.png

怎么样?是不是感觉有那么一点不对劲的地方(为了看得更明显我在外面加了一个圈),文字有一点“偏上”的赶脚。没错,这都是因为基线惹的祸,刚才说了y坐标是基线的位置,也就是说,文字的基线在竖直居中的位置,而文字的正中心则并没有做到竖直居中,明显是有一个偏移量的。重点来了,如何计算这个偏移量呢?
有两种方式

第一种 通过Paint.getTextBounds()方法

先讲一下方法

  • getTextBounds(String text, int start, int end, Rect bounds)
    参数里,text 是要测量的文字,start 和 end 分别是文字的起始和结束位置,bounds 是存储文字显示范围的对象,方法在测算完成之后会把结果写进 bounds
    知道了方法怎么用,我就先简单地讲一下思路,通过getTextBounds获得文字的边框Bounds,然后通过Bounds.top+Bounds.bottom/2,这个就是偏移量,最后减去就可以了,不多说,直接上代码
        Rect bounds=new Rect();
        String text="abcdefg";
        mPaint.getTextBounds(text,0,text.length(),bounds);
        float offSet=(bounds.top+bounds.bottom)/2;
        canvas.drawText("text",centerX,centerY-offSet,mPaint);

再看一眼效果图


img_a5dc69b2fe92b663fdc5366e5b1e7e53.png
效果图

问题来了,这里为什么是bounds.top+bounds.bottom,而不是bounds.bottom-bounds.top?最后为什么要减掉偏移量?

img_822ea23ee9fa875606143991e627757a.png
计算偏移量的方法

首先,调用getTextBounds()方法会在文字形成一个边框,同时还会形成一个坐标系(如图中绿色所画),正是在这个坐标系下,top是负值,bottom是负值,你可以把这两个值理解为向量,之所以是(bounds.top+bounds.bottom)/2,因为我们要算得是文字的 中间位置,而不是文字的高度的一半,之所以要减去,就像图中标注的一样,我们现在要把文字向 移动,而中间位置的方法是负,也就是向 ,方向相反,所以要减去偏移量,我们再从数学的角度分析一下,减去一个负值,相当于加上一个正值,因此,是会把文字向下移动的,这样,文字就居中了。

第二种 通过FontMetircs

获取FontMetircs的方法:
FontMetrics 是个相对专业的工具类,它提供了几个文字排印方面的数值:ascent, descent, top, bottom, leading
ascent和descent分别代表了普通文字的顶部和底部,而top和bottom则代表了所有字符的顶部和底部,有些特殊字符可能会超过ascent和descent,但永远不会超过top和bottom
下面我还是画个图来描述一下吧

img_afec251f307cbb9fd56b39d9b2d4a6e5.jpe

图中内部的两条线分别是ascent和descent,外部是top和bottom。
注意,这几条线是FontMetrics规定好的,也就是说这四个值是 固定不变 的,无论你绘制的内容如何变,这几个值都不会变,这一点很重要,要记住了。
在这里计算偏移量我们只需要用到ascent和descent,计算的方法跟使用getTextBounds()是一样得,不多说,直接上代码

        Paint.FontMetrics fontMetrics=new Paint.FontMetrics();
        mPaint.getFontMetrics(fontMetrics);
        float offset=(fontMetrics.descent+fontMetrics.ascent)/2;
        canvas.drawText(text,centerX,centerY-offset,mPaint);

效果跟getTextBounds差不多,就不上图了

getTextBounds()和FontMetircs的区别和使用场景

刚才分别介绍了这两种方式,这时候你可能会问了,什么时候用哪一种,还是无所谓,都可以。其实这两个方法还是存在一点区别的

  • getTextBounds() 随着绘制内容的变化,导致中间位置也变化,即(bounds.top+bounds.bottom)/2的值是会变得
  • FontMetircs 固定的文字测量工具,中间位置不会随绘制内容发生改变

知道了其中的区别,关于二者的应用场景也就了解了

  • 绘制内容会产生变化的情况下,比如动态地把“bbbb”改成了“aaaa”或者其他文字,我们就用FontMetircs测量;

  • 绘制内容不发生如何变化的,就直接用getTextBounds()就可以了

总结

以上就是关于文字绘制的全部知识,基本该注意的地方都讲到了,最近事比较多,先写这么多了哈,有什么问题随时欢迎大家评论留言。

我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。

目录
相关文章
|
1月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
29 1
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
107 0
|
1月前
|
XML 前端开发 Android开发
Android:UI:Drawable:View/ImageView与Drawable
通过本文的介绍,我们详细探讨了Android中Drawable、View和ImageView的使用方法及其相互关系。Drawable作为图像和图形的抽象表示,提供了丰富的子类和自定义能力,使得开发者能够灵活地实现各种UI效果。View和ImageView则通过使用Drawable实现了各种图像和图形的显示需求。希望本文能为您在Android开发中使用Drawable提供有价值的参考和指导。
42 2
|
1月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
1月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
41 5
|
2月前
|
缓存 数据处理 Android开发
在 Android 中使用 RxJava 更新 View
【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
|
2月前
|
缓存 调度 Android开发
Android 在子线程更新 View
【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
43 2
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
29 2
|
Android开发
自定义android 4.0以上的对话框风格
做个笔记,这里是Dialog的风格,如果是用AlertDialog创建的,不能直接用。在styles.xml的写法: 22sp @color/font_green 1 true @st...
709 0