自定义View之Paint - 绘制文本

字体属性及测量(FontMetrics).doc 立即下载

FontMetrics

FontMetrics是Paint的一个内部类,用于描述给定文本大小的字体的各项参数:

public static class FontMetricsInt {
    /**
     * 在给定字体大小的文本中,最高字符的顶部在基线上方的最大距离。
     */
    public float   top;
    /**
     * 对于单行文本,文本在基线上方的距离
     */
    public float   ascent;
    /**
     * 对于单行文本,文本在基线下方的距离
     */
    public float   descent;
    /**
     * 在给定字体大小的文本中,最低字符的顶部在基线上方的最大距离。
     */
    public float   bottom;
    /**
     * 两行文本之间的距离
     */
    public float   leading;

    @Override public String toString() {
        return "FontMetricsInt: top=" + top + " ascent=" + ascent +
                " descent=" + descent + " bottom=" + bottom +
                " leading=" + leading;
    }
}

从网上找了个图片来描述各个参数:

BaseLine是基线,Android在绘制文本的基础行。为什么会有基线这个概念呢?外文并不像中文这样,它们是由字母而组成的,而多数字母排列是沿着基准线,但是,像”p”或者”y”之类的字母会超过基线向下延伸,超过的部分称为降部,反之,基线以上的称为升部。Baseline往上至字符“最高处”的距离我们称之为ascent(上坡度),Baseline往下至字符“最低处”的距离我们称之为descent(下坡度)。又因为Android系统中,对于坐标系的定义,Y值增加向下延伸,因此,获取到的descent为正值,而ascent为负值。

leading是两行文本之间的距离,官方并没有明确的解释,应该是上一行的descent与下一行的ascent之间的距离。

关于top、bottom描述的比较模糊,对于top而言,是指最高字符的顶部在基线上方的最大距离,可是,又与ascent的定义有所冲突。借鉴下TextView对于文本的控制,其总会为文本留下部分内边距,因为TextView在绘制文本时会考虑一些特殊符号,比如音调符号。我们是不是可以这样理解:

  • top = ascent + 文本上方预留边距
  • bottom = descent + 文本下方预留边距

为了验证FontMetrics中的各个参数,现自定义View,绘制 “yearξτβбшㄎěǔぬも测试a”这个字符串:

override fun onDraw(canvas: Canvas?) {
    super.onDraw(canvas)

    paintText.apply {
        textSize = 96f
        strokeWidth = 3f
    }

    // FontMetrics对象
    val fontMetrics = paintText.fontMetricsInt
    val topY = fontMetrics.top
    val ascentY = fontMetrics.ascent
    val descentY = fontMetrics.descent
    val bottomY = fontMetrics.bottom
    val leading = fontMetrics.leading

    Log.i("123", "topY: $topY")
    Log.i("123", "ascentY: $ascentY")
    Log.i("123", "descentY: $descentY")
    Log.i("123", "bottomY: $bottomY")
    Log.i("123", "leading: $leading")

    val baseLine = 128f

    val widthText = paintText.measureText(text1)

    canvas?.drawText(text1, 64f, baseLine, paintText)

    paintLine.strokeWidth = 3f

    // baseLine
    paintLine.color = resources.getColor(android.R.color.holo_red_dark)
    canvas?.drawLine(0f, baseLine, 128f + widthText, baseLine, paintLine)

    // top
    paintLine.color = resources.getColor(R.color.colorTop)
    canvas?.drawLine(0f, topY + baseLine, 128f + widthText, topY + baseLine, paintLine)

    // ascent
    paintLine.color = resources.getColor(R.color.colorAscent)
    canvas?.drawLine(0f, ascentY + baseLine, 128f + widthText, ascentY + baseLine, paintLine)

    // descent
    paintLine.color = resources.getColor(R.color.colorDescent)
    canvas?.drawLine(0f, descentY + baseLine, 128f + widthText, descentY + baseLine, paintLine)

    // bottom
    paintLine.color = resources.getColor(R.color.colorBottom)
    canvas?.drawLine(0f, bottomY + baseLine, 128f + widthText, bottomY + baseLine, paintLine)

    // leading
    paintLine.strokeWidth = leading.toFloat()
    paintLine.color = resources.getColor(R.color.colorLeading)
    canvas?.drawLine(0f, bottomY.toFloat(), 128f + widthText, bottomY.toFloat(), paintLine)

}

效果图:

这里写图片描述

Log如下:

topY: -102 
ascentY: -8
descentY: 2
bottomY: 27
leading: 0 

测量文本宽度

当指定文本的字体大小以后,Paint提供了两种测量文本宽度的方式:

  • breakText
  • measureText

breakText和measureText都可以测量指定文本的宽度。与measureText不同的是,breakText可以指定文本的最大宽度,当文本的宽度超过最大宽度时,会停止测量。如果传递的measuredWidth不为null,会将文本的宽度保存。

例如:在自定义View - PaintTextAPIView中,绘制了字符串”yaξβбшㄎěǔぬ中”,每个字符的大小为96f。

class PaintTextAPIView : View {

    private val text: String = "yaξβбшㄎěǔぬ中"

    ***

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        paintText.apply {
            textSize = 96f
            strokeWidth = 3f
        }

        val baseLine = 128f

        // 获取View的宽度
        val width = width
        Log.i("123", "view的宽度: $width")

        val widthText = paintText.measureText(text)
        Log.i("123", "文本的宽度: $widthText")
        Log.i("123", "文本的个数: ${text.length}")

        val measuredWidth = kotlin.FloatArray(1)
        val countBreak = paintText.breakText(text, false,  540f, measuredWidth)
        Log.i("123", "满足测量的条件的字符个数: $countBreak")
        Log.i("123", "measuredWidth: ${measuredWidth.toList()}")

        canvas?.drawText(text, 64f, baseLine, paintText)
    }
}

在上述示例中,通过Paint的setTextSize方法指定了文本中字符的大小,然后调用了measureText方法,测量了文本的宽度为722f。在调用breakText方法时,指定的最大宽度为540f。当测量到第几个字符时的宽度为530f,如果在再加上第10个字符时,必然超过540f。此时停止了测量文本的宽度,返回了满足条件的字符个数,并将满足条件的文本的宽度保存在measuredWidth中。

view的宽度: 960
文本的宽度: 722.0
文本的个数: 11
满足测量的条件的字符个数: 9
measuredWidth: [530.0]

setLetterSpacing

该方法是在API 21新增的,最低使用API也是21.它用于设置文本的字符之间的间距,其默认值为0。值得注意的是它的单位不再是px或者dp,而是EM(1EM相当于当前字体的尺寸)。

比如, 将文本的字符间距设置为1EM:

paintText.letterSpacing = 1f

效果图:

这里写图片描述

此时,如果paintText设置的字体大小为14dp,那么它们的行间距应为14dp。假如将setLetterSpacing设置为1.5f,此时的字体间距应为21dp。

setStrikeThruText

该方法用于设置文本带有删除线。

这里写图片描述

setTextAlign(Paint.Align align)

该方法用于设置文本的对齐方式。在Paint.Align中定义了一系列的对齐方式:

  • CENTER:居中对齐
  • LEFT:居左对齐
  • RIGHT:居右对齐

现定义了一个AlignView,一一使用了不同的对齐方式:

class AlignView : View {

    ***

    private fun initData() {
        paintDefault = Paint()

        paintDefault.apply {
            textSize = 48f
        }

        paintCenter = Paint(paintDefault)
        paintCenter.textAlign = Paint.Align.CENTER

        paintLeft = Paint(paintDefault)
        paintLeft.textAlign = Paint.Align.LEFT

        paintRight = Paint(paintDefault)
        paintRight.textAlign = Paint.Align.RIGHT

        paintLine = Paint()
        paintLine.apply {
            color = resources.getColor(R.color.colorLeading)
            strokeWidth = 3f
        }
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas?.drawText(text, 144f, 72f, paintDefault)
        canvas?.drawText(text, 144f, 144f, paintCenter)
        canvas?.drawText(text, 144f, 216f, paintLeft)
        canvas?.drawText(text, 144f, 288f, paintRight)

        canvas?.drawLine(144f, 0f, 144f, 360f, paintLine)
    }
}

从效果图上,我们清晰的看出,默认的对齐方式是居左对齐。这个方法影响的是文本的哪一部分位于绘制的起始点。在调用drawText绘制文本时,要尤其注意绘制初始的X坐标,要不然就会出现文本绘制混乱,影响显示。

  • CETER: (Xstart, Ystart)
  • LEFT: (Xstart + text.lentgh/2, Ystart)
  • RIGHT: Xstart + text.lentgh, Ystart)

这里写图片描述

setTextScaleX(float scaleX)

该方法用于设置Paint的字体的比例因子,默认为1f.当大于1时,表示横向拉伸;当小于1时,表示横向压缩。

这里写图片描述

setTextSize(float size)

该方法用来设置文本的字体大小,不必多说…

setTextSkewX(float skewX)

该方法用来设置文本的偏移因子,默认值为0.对于近似倾斜的文本,使用-0.25。正数表示向左倾斜,负数表示向右倾斜。

这里写图片描述

setUnderlineText (boolean underlineText)

该方法用来设置是否绘制文本的下划线。其中,underlineText表示是否显示下画线,ture表示显示下画线,false表示不显示下画线。

这里写图片描述

setTypeface(Typeface typeface)

该方法用来字体的样式。对于Typeface不了解的,可参考Android中的字体设置-Typeface.

val typeface = Typeface.defaultFromStyle(Typeface.ITALIC or Typeface.BOLD)
tcv.setTypeface(typeface)

这里写图片描述

其他API

  • setSubpixelText(boolean subpixelText):设置该项为true,将有助于文本在LCD屏幕上的显示效果
  • setFontFeatureSettings(String settings):设置字体功能设置。 格式与CSS font-feature-settings属性相同
  • setFontVariationSettings(String fontVariationSettings):设置TrueType或OpenType字体变体设置




若想了解更多Paint相关的内容,请跳入: 自定义View系列文章目录




如果觉得我的文章对您有用,请随意点赞、评论。您的支持将鼓励我继续创作!

fMRI数据处理:从DICOM到NIFTI(下) 上一篇我们完成了对原始DICOM的数据整理,将其整理为了BIDS目录结构。作为从从DICOM到NIFTI的最后一篇,当然是介绍如何批量将DICOM格式转NIFTI格式啦!从DICOM到NIFTI系列就完成啦!撒花★,°.°★。从核磁机器把数据拷回来——到整理成BIDS格式——到批量转格式;我们fMRI数据处理的第一步就算是正式迈出去啦!接下来的内容,敬请期待吧~ 阅读详情

相关推荐

Multisim仿真电路:(十二)MOS管缓启动电路设计与优化

本文详细介绍了基于Multisim的MOS管缓启动电路设计与优化方法。通过分析米勒平台效应,探讨RC参数选择、多级设计和有源电路等技巧,有效抑制冲击电流并优化开关损耗。文章结合仿真实例,提供实用的设计策略和实际应用注意事项,帮助工程师提升电源管理系统的可靠性。

pytorch8learner的博客 237

Android字体度量(FontMetrics)

基本概念 字体的度量,是指对于指定字号的某种字体,在度量方面的各种属性,其描述参数包括: baseline:字符基线ascent:字符最高点到baseline的推荐距离top:字符最高点到baseline的最大距离descent:字符最低点到baseline的推荐距离bottom:字符最低点到baseline的最大距离leading:行间距,即前一行的descent与下一行的asc

flyeek 1万+

Halcon形状模板匹配实战:inspect_shape_model参数优化指南

本文深入解析Halcon形状模板匹配中inspect_shape_model参数的优化技巧,涵盖NumLevels和Contrast参数的实战应用。通过具体案例展示如何平衡匹配速度与精度,帮助开发者高效调试形状模型,提升工业视觉检测的准确性和效率。

weixin_30342209的博客 618

Paint画笔相关

1:Paint.FontMetricsInt、Paint.FontMetrics字体高度测量 都是测量字体高度相关的类,2个都类功能一样,一个返回int值,一个返回float值 他与paint设置的size和typeface(字体类型)有关,这些属性改变时会影响获取到的值 4个参数:ascent、bottom、descent、leading、top Paint paint = new ...

一个IT屌丝的专栏 685

SDR实战(四)-AD9361使用手册(三)

本节定义了并行数据端口和串行外设接口(SPI),它们使得AD9361与基带处理器(BBP)之间能够传输数据和控制/状态信息。图63展示了这些接口,并提供了AD9361和BBP在宽带无线系统中使用方式的高级概述。数据接口以两种模式之一运行:兼容标准CMOS模式或兼容低压差分信号(LVDS)模式。每个接口都具有以下部分描述的独特特性。使用CMOS模式时:保持了单端-CMOS逻辑兼容性。可以使用一个或两个数据端口。使用两个端口可以提高数据吞吐量。

hutx0924的博客 6242

224G PAM-4 通道的 PCB 和封装设计

该行业正在努力实现层厚非常低的 sub-Dk = 3 材料,以及更先进的加工,这将使封装和 PCB 中的透射电镜截止值更高。当回波损耗占主导地位时,我们基本上需要去除沿互连产生阻抗失配的任何元件,就像上面描述的更光滑的铜和更低的 Dk 值一样。第二个影响是传输线阻抗匹配在 56 GHz 范围内的非常高的频率下非常困难的主要原因之一,另一个因素是 Tx 或 Rx 封装/缓冲器中的寄生效应。由于 PCB 和封装中的长度刻度,这是 BGA 上的焊盘、过孔和球等小结构开始在输入阻抗中产生明显偏差的频率范围。

jkh920184196的博客 840

Android字符串进阶之三:字体属性及测量(FontMetrics)

http://www.runoob.com/w3cnote/android-tutorial-shadowlayer.html 本节引言: 在Android基础入门教程——8.3.1 三个绘图工具类详解Paint的方法参数那里我们就接触到了这样几个东西:Paint.Style,Paint.Cap,Paint.Join等,这些都是Paint中的一些枚举值,相关方法我们可以通过设置这些枚举

山城木府 2759

【深度学习基础】Temporal Fusion Transformer

从下向上看:全连接(Dense) → ELU(指数线性激活函数(比relu好点,有利于模型收敛)) → 全连接(Dense) → 门控线性单元(Gate)(Gated Linear Units (GLUs)) → Layernorm。:一方面,它可以进行静态上下文变量和动态变量的融合,另一方面,通过门控进行了特征选择操作,门控体现在GLU(门控线性单元)中,用了sigmoid控制信息的通过程度,具有良好的适应性,能够自动选择有效信息,自适应地调整网络复杂性。输入:主输入,可选的上下文向量c。

weixin_41838721的博客 1224

自定义控件之绘图篇( 五):drawText()详解

前言:但行好事,莫问前程。只需努力每一天。 相关文章: 《Android自定义控件三部曲文章索引》: http://blog.youkuaiyun.com/harvic880925/article/details/50995268 long long ago,有讲过有关Canvas绘图的系列知识,当时着重在基本绘图要领和canvas的保存与回退上,对drawText没有细讲,但DrawText这...

启舰 7万+

三相电机控制中的端电压、相电压与线电压波形解析

本文深入解析了三相电机控制中端电压、相电压与线电压的核心概念与波形差异。通过对比方波控制、SPWM和SVPWM三种主流控制策略下的实测波形特征,揭示了不同控制逻辑对电压波形(如梯形波、正弦波、马鞍波)的影响。文章重点阐述了SVPWM控制如何通过生成马鞍波形端电压来提高直流母线电压利用率,并提供了实用的波形测量与调试指南,帮助工程师深入理解电机控制原理并进行有效调试。

qsc901234567的博客 1394

超级详细!!!新手使用AutoDL跑深度学习(MixVPR项目)的学习记录

新手第一次在AutoDL上跑深度学习的实验,遇到一些问题,简单记录一下。如果大家发现问题,欢迎和我讨论。

weixin_45152283的博客 5万+

自定义View——Paint 之 文本绘制

文本相关操作 对于文本相关的API,有很多,使用也很简单,这里简单罗列一下: setTextSize(float textSize) 设置文字大小 setUnderlineText(boolean underlineText) 设置下划线 setStrikeThruTex...

M-Ellen的博客 953

FPGA原理与结构(3)——存储单元(Storage Elements)

触发器,锁存器,寄存器,为什么xilinx推荐高电平复位,为什么latch依然存在,FPGA中的触发器与锁存器

apple_53311083的博客 2961

android 自定义paint,Android自定义View之paint(一)

学习自定义view,就是将view绘成自己想要的样子,自然就要有绘画的工具,那就是Paint。**1. 构造函数 ** Paint() Create a new paint with default settings. 创建一个默认的Paint对象 Paint(int flags) Create a new paint with the specified flags. 创建一个指定flag的Pa...

weixin_39764487的博客 298

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Android自定义View之Paint绘制文本

FontMetrics

老头儿ii的博客 489

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Android自定义View实现圆弧进度效果

前言:Android开发中,自定义View实现自己想要的效果已成为一项必备的技能,当然自定义View也是Android开发中比较难的部分,涉及到的知识有Canvas(画布),Paint(画笔)等,自定义控件分为三种:一是直接继承自View,完全的自定义;二是在原有控件的基础上进行改造,达到自己想要的效果;还有一种就是自定义组合控件,将已有的控件根据自己的需要进行组合实现的效果。本人对自定义View...

轻描时光 403

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Android自定义view之基础canvas.drawXXX方法

        做Android不知不觉也有些年头了,但是对于自定义view却没有真正的好好研究或者实践过,可能是好用的库太多,自己就不想去想着自己去实现一些效果,不过别人的终究是别人的,毕竟“纸上得来终觉浅,绝知此事要躬行”,所以最近就花了些时间从最基础的开始实践,以此博客做一些记录。        说起自定义view大家肯定首先想到的就是canvas和paint,canvas大家一般都直译为“...

和小胖 925

自定义View之仿QQ运动步数进度效果

前言 今天接着上一篇来写关于自定义View方面的东西,因为我近期也是在学习整理这方面的知识点,所以我把学习的笔记都写成博文放到这个Android自定义View的专栏里了,仅作为自己学习笔记所用,今天的内容是关于Paint画笔方面的一个应用,做一个Demo——仿QQ运动步数进度效果。 一、案例效果分析 首先上一张效果图,大家一起来看一下: 通过上面的这张图,我们来分析一下,该如何去实现...

江湖人陆仁甲 557

自定义View详解

一、前言 自定义View可能大家平常都会使用到,但是一般都是复制一个别人的代码,还没有过完全自己写的自定义view吧。自定义view一般使用在自定义进度条时会用到。自定义可以简单理解为封装的TextView、Button等都是继承自View。 二、概述 自定义View需要学习三个变量属性;Canvas(画布)、Paint(画笔)、Rect(尺寸) 1、Canvas(画布)类 可以用来实现...

会飞的鱼儿的博客 1437

Android Canvas.DrawText文本绘制

Android DrawText

YK 2035

重学 Android 自定义 View 系列:动手实现专属 TextView

前言前面一篇介绍了自定义View的基础概念(皮毛),接下来全部是自定义View实战,让我们一起开启自定义View之旅吧!1. 实现目标本篇将实现一个自定义的TextView,通过自定义属性让我们可以配置文本内容、颜色、字体大小。主要是掌握自定义View中画文字的基础概念。在 attrs.xml 中定义自定义属性在自定义Vi...

cnzzs的博客 939

View 的绘制流程(一)

每个View 绘制过程中,基本上都经历 3 个主要步骤:1、onMeasure()— 测量 ( 宽度高度 )2、onLayout()— 布局 ( 安排在哪个位置 )3、onDraw()— 显示内容自定义View的引用 1、可以从View中继承,自定义一个视图public class MyView extends View { /** * java的动态布局 * 一般用于

RylynnKang 的博客 251

自定义View

自定义View中最重要的两个东西就是画笔和画布。首先来说一下画笔 Paint。 Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色,样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法,大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关。 1.图形绘制 1.setARGB(inta,in...

weixin_34364135的博客 102

Android画图系列(二)——自己定义View绘制基本图形

这个系列主要是介绍下Android自己定义View和Android画图机制。自己能力有限。假设在介绍过程中有什么错误。欢迎指正 前言 在上一篇Android画图系列(一)——自己定义View基础中我们了解自己定义View相关的基本知识。只是,这些东西依然还是理论,接下来...

aoe41606的博客 123
上一篇: 自定义View之Paint - 基础
下一篇: 自定义View系列文章目录
行云间
博客等级 码龄12年 438粉丝 173原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值