自定义View之Paint
来源:互联网 发布:网络营业执照办理 编辑:程序博客网 时间:2024/05/19 15:39
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: -8descentY: 2bottomY: 27leading: 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满足测量的条件的字符个数: 9measuredWidth: [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系列文章目录
如果觉得我的文章对您有用,请随意点赞、评论。您的支持将鼓励我继续创作!
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 自定义View之Paint
- 【Paint】Android 自定义View之Paint篇(更新中...)
- 自定义view(二):onDraw 之 Paint
- 自定义View (三) :onDraw 之 paint 画笔
- 自定义View(一)---Paint
- android 自定义View之 Paint类的介绍
- Android自定义View——Paint之Xfermode
- Android 自定义View之路——Paint
- 打造前端 Deepin Linux 工作环境——安装最新版本的火狐firefox浏览器
- 171106-寻找1000以内的素数【连续第十四天】
- 20171106即将开启的一段艰难的旅程
- python里 192.08 + 5.81 = 197.89 ?
- logrotate--Linux日志文件总管
- 自定义View之Paint
- android Activity实现底部滑动弹出窗口及源码下载地址
- h2o.ai源码解析(3)—CPU管理
- 程序员的幽默:最糟糕音量调节工具设计大赛
- Git 【初次提交代码到空的远端仓库】
- 6、线程的概念和多线程模型
- spring aop
- AndoridStudio更换SVN链接
- MySQL嵌套查询(子查询)