鸿蒙开发-想调整字体效果?Font类的大小、粗体和样式设置
本文介绍了如何在绘画类APP中使用HarmonyOS的drawing.Font类来控制文字样式。主要内容包括: 创建Font实例:通过new drawing.Font()创建字体对象 基础属性设置: setSize()设置字体大小(单位px) enableEmbolden()开启/关闭粗体效果 setSkewX()控制文字倾斜(正数左斜,负数右斜) setScaleX()水平缩放文字 高级渲染控制
做绘画 APP 时怎么控制文字的大小、粗细和倾斜?Font 类帮你搞定
你有没有遇到过这种情况:在做一个绘画类 APP 的时候,想让用户可以在画布上自由地写字、标注,但文字的大小、粗细、倾斜角度都需要灵活控制?比如用户想写个大标题用粗体,写个小注释用细体,或者想让文字有点"意大利斜体"的感觉?
这时候你就需要 HarmonyOS 的 drawing.Font 类了。简单说,这个类就是用来描述"字型绘制时所使用的属性"的——字体大小、粗体、倾斜、边缘效果等等,全都由它来管。
Font 类功能总览
下面是 Font 类的主要功能分类,帮助你快速了解它能做什么:
先把 Font 创建出来
要用 Font,第一步当然是创建一个实例。别忘了导入 drawing 模块:
import { drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
就这么简单,一行 new drawing.Font() 搞定。创建出来的是一个默认的 Font 对象,后面你可以根据需要给它设置各种属性。
设置字体大小:setSize
这是最基础的操作了。你想让文字多大,就调用 setSize:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.setSize(5);
这里 setSize(5) 把字体大小设成了 5px。注意,这个单位是物理像素 px,不是逻辑像素。也就是说在高分屏上,5px 可能看起来非常小。
有个细节要注意:如果你传一个负数进去,字体大小会被重置为 0,而字体大小为 0 的时候,绘制的文字是不会显示的。所以别传负数,除非你故意想让文字"消失"。
想读取当前字体大小?用 getSize:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.setSize(5);
let fontSize = font.getSize();
getSize() 返回的是一个浮点数,就是你之前设置的那个值。
让文字变粗:enableEmbolden
有时候你想让文字加粗显示,比如标题或者重点标注。Font 提供了 enableEmbolden 方法来开启粗体效果:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.enableEmbolden(true);
传 true 开启粗体,传 false 关闭。这个粗体效果是软件模拟的,不是说你必须用一个粗体字体文件,它会自动把普通字体"加粗"渲染。
想检查当前有没有开启粗体?用 isEmbolden:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.enableEmbolden(true);
console.info("values=" + font.isEmbolden());
返回 true 说明粗体已开启。
让文字倾斜:setSkewX
想做出"斜体"效果?用 setSkewX 就行。这个方法设置的是文字在 X 轴方向上的倾斜比例:
import { RenderNode } from '@kit.ArkUI';
import { common2D, drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const canvas = context.canvas;
const pen = new drawing.Pen();
pen.setStrokeWidth(5);
pen.setColor({alpha: 255, red: 255, green: 0, blue: 0});
canvas.attachPen(pen);
let font = new drawing.Font();
font.setSize(100);
font.setSkewX(1);
const textBlob = drawing.TextBlob.makeFromString("hello", font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
canvas.drawTextBlob(textBlob, 200, 200);
}
}
这里 setSkewX(1) 让文字往左边倾斜。参数是正数就往左斜,负数就往右斜。值越大,倾斜越明显。
想读取当前的倾斜值?用 getSkewX:
import {drawing} from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
font.setSkewX(-1)
console.info("values=" + font.getSkewX());
让文字变宽变窄:setScaleX
除了倾斜,你还可以让文字在水平方向上"拉伸"或"压缩"。setScaleX 设置的是 X 轴的缩放比例:
import { RenderNode } from '@kit.ArkUI';
import { common2D, drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const canvas = context.canvas;
const pen = new drawing.Pen();
pen.setStrokeWidth(5);
pen.setColor({alpha: 255, red: 255, green: 0, blue: 0});
canvas.attachPen(pen);
let font = new drawing.Font();
font.setSize(100);
font.setScaleX(2);
const textBlob = drawing.TextBlob.makeFromString("hello", font, drawing.TextEncoding.TEXT_ENCODING_UTF8);
canvas.drawTextBlob(textBlob, 200, 200);
}
}
setScaleX(2) 意味着文字在水平方向上被拉伸到原来的 2 倍。如果你想让文字变窄,可以传一个小于 1 的值,比如 0.5。
读取当前缩放比例:
import {drawing} from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
font.setScaleX(2);
console.info("values=" + font.getScaleX());
亚像素渲染:enableSubpixel
这个功能可能听起来有点"技术宅",但它确实能让你的文字看起来更平滑。亚像素渲染(Subpixel Rendering)是一种利用屏幕像素排列特性来提升文字清晰度的技术。
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.enableSubpixel(true);
开启之后,文字边缘会更加细腻,不会那么"锯齿"。不过要注意,这个效果在不同屏幕上可能表现不一样,因为它是和屏幕的物理像素排列相关的。
检查是否开启了亚像素渲染:
import {drawing} from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
font.enableSubpixel(true)
console.info("values=" + font.isSubpixel());
线性缩放:enableLinearMetrics
线性缩放是什么意思呢?简单说,就是让字体在缩放的时候保持"线性"关系,不会因为缩放而产生额外的变换效果。
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.enableLinearMetrics(true);
在做一些需要精确控制文字大小的场景(比如图表标注、CAD 软件)时,开启线性缩放可以保证文字在不同缩放级别下的表现一致。
检查状态:
import {drawing} from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
font.enableLinearMetrics(true)
console.info("values=" + font.isLinearMetrics());
边缘效果:setEdging
文字的边缘处理有几种模式,setEdging 可以控制文字边缘的抗锯齿效果:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.setEdging(drawing.FontEdging.SUBPIXEL_ANTI_ALIAS);
FontEdging 有几个可选值,SUBPIXEL_ANTI_ALIAS 是亚像素抗锯齿,效果最细腻。你可以根据实际需求选择不同的边缘处理模式。
读取当前边缘效果:
import { drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
console.info("values=" + font.getEdging());
轮廓效果:setHinting
Hinting 是字体渲染中的一个重要概念,它决定了字体轮廓如何对齐到像素网格上:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.setHinting(drawing.FontHinting.FULL);
FontHinting.FULL 表示完全 hinting,文字会尽量对齐到像素网格上,在低分辨率屏幕上看起来更清晰。如果你追求更"原汁原味"的字体轮廓,可以用 NONE。
读取当前 hinting 设置:
import { drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
console.info("values=" + font.getHinting());
测量文本宽度:measureText
这个方法在实际开发中用得非常多。你想知道一段文字在当前字体设置下占多宽,就用 measureText:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.measureText("drawing", drawing.TextEncoding.TEXT_ENCODING_UTF8);
你需要传入文本内容和编码格式。返回值是一个浮点数,表示文本的宽度(单位是 px)。
有个小提示:这个方法测量的是"原始字符串"的宽度。如果你的文本经过了排版处理(比如自动换行),那测量结果可能和实际显示的宽度不一样。那种情况下建议用 measure.measureText 来替代。
测量单个字符宽度:measureSingleCharacter
如果你只需要测量一个字符的宽度,用这个方法更高效:
import { RenderNode } from '@kit.ArkUI';
import { drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const canvas = context.canvas;
const font = new drawing.Font();
font.setSize(20);
let width = font.measureSingleCharacter("你");
}
}
注意参数必须是单个字符,字符串长度为 1。如果当前字体不支持这个字符,系统会自动退回到系统字体来测量。
还有一个更高级的版本 measureSingleCharacterWithFeatures,可以传入字体特征参数:
import { RenderNode } from '@kit.ArkUI';
import { drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const font = new drawing.Font();
font.setSize(20);
let fontFeatures : Array<drawing.FontFeature> = [];
fontFeatures.push({name: 'calt', value: 0});
let width = font.measureSingleCharacterWithFeatures("你", fontFeatures);
}
}
FontFeature 可以让你控制一些 OpenType 字体特性,比如连字、数字样式等。传空数组就使用字体文件里的默认设置。
获取文本字符数量:countText
想知道一个字符串里有多少个字符?用 countText:
import { drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
let resultNumber: number = font.countText('ABCDE');
console.info("count text number: " + resultNumber);
这个方法会正确处理各种编码的字符,包括中文、emoji 等。
文本转字形索引:textToGlyphs
这个方法把文本字符串转换成字形索引数组。字形(Glyph)是字体文件中实际存储的字符图形,一个字符可能对应一个或多个字形:
import { drawing } from '@kit.ArkGraphics2D';
let font : drawing.Font = new drawing.Font();
let text : string = 'hello world';
let glyphs : number[] = font.textToGlyphs(text);
console.info("drawing text toglyphs OnTestFunction num = " + glyphs.length );
返回的数组里每个元素都是一个字形索引。你可以用这些索引来获取每个字形的宽度、边界等信息。
获取字形宽度:getWidths
拿到字形索引之后,你可以获取每个字形的宽度:
import { drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
let text: string = 'hello world';
let glyphs: number[] = font.textToGlyphs(text);
let fontWidths: Array<number> = font.getWidths(glyphs);
for (let index = 0; index < fontWidths.length; index++) {
console.info("get fontWidths[", index, "]:", fontWidths[index]);
}
这个方法返回一个数组,长度和传入的字形索引数组一样,每个元素对应一个字形的宽度。
获取字形边界:getBounds
除了宽度,你还可以获取每个字形的完整边界矩形:
import { common2D, drawing } from '@kit.ArkGraphics2D';
let font: drawing.Font = new drawing.Font();
let text: string = 'hello world';
let glyphs: number[] = font.textToGlyphs(text);
let fontBounds: Array<common2D.Rect> = font.getBounds(glyphs);
for (let index = 0; index < fontBounds.length; index++) {
console.info("get fontWidths[", index, "] left:", fontBounds[index].left, " top:", fontBounds[index].top,
" right:", fontBounds[index].right, " bottom:", fontBounds[index].bottom);
}
每个 Rect 包含 left、top、right、bottom 四个值,描述了字形的边界框。这在做文字碰撞检测、自定义排版时非常有用。
获取文字轮廓路径:getTextPath
这个功能很有意思——它能把文字转换成路径(Path)。也就是说,你可以把文字当成图形来处理:
import { drawing } from '@kit.ArkGraphics2D';
import { buffer } from '@kit.ArkTS';
import { RenderNode } from '@kit.ArkUI';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const canvas = context.canvas;
let font = new drawing.Font();
font.setSize(50);
let myString: string = "Hello";
let length: number = buffer.from(myString).length;
let path = font.getTextPath(myString, length, 0, 100);
canvas.drawPath(path);
}
}
这里有个关键点:byteLength 参数是文本的字节长度,不是字符数量。所以用 buffer.from(myString).length 来获取。x 和 y 是文字在画布上的起始坐标。
拿到 Path 之后,你可以对它做各种操作——描边、填充、甚至做路径动画。
获取单个字形的路径:createPathForGlyph
如果你想更精细地控制,可以获取单个字形的路径:
import { RenderNode } from '@kit.ArkUI';
import { drawing } from '@kit.ArkGraphics2D';
class DrawingRenderNode extends RenderNode {
draw(context : DrawContext) {
const canvas = context.canvas;
let font = new drawing.Font();
font.setSize(50)
let text: string = '你好';
let glyphs: number[] = font.textToGlyphs(text);
for (let index = 0; index < glyphs.length; index++) {
let path: drawing.Path = font.createPathForGlyph(glyphs[index])
canvas.drawPath(path)
}
}
}
这段代码把"你好"两个字分别转换成路径,然后逐个绘制。你可以对每个字形的路径做不同的处理,比如给每个字不同的颜色、做不同的动画效果。
设置和获取字体样式:setTypeface / getTypeface
Font 可以关联一个 Typeface(字体样式),包括字体名称、粗细、斜体等:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
font.setTypeface(new drawing.Typeface());
读取当前关联的字体:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
let typeface = font.getTypeface();
Typeface 的具体用法我们在后面的文章里会详细讲。
获取字体度量信息:getMetrics
getMetrics 返回一个 FontMetrics 对象,里面包含了字体的各种度量信息:
import { drawing } from '@kit.ArkGraphics2D';
let font = new drawing.Font();
let metrics = font.getMetrics();
FontMetrics 里有 ascent(上升高度)、descent(下降高度)、leading(行间距)等信息,这些在做自定义文字排版时非常关键。
基线对齐:setBaselineSnap
这个功能控制文字基线是否与像素对齐:
import { drawing } from '@kit.ArkGraphics2D';
let font : drawing.Font = new drawing.Font();
font.setBaselineSnap(true);
console.info("drawing font isBaselineSnap: " + font.isBaselineSnap());
开启基线对齐后,当画布矩阵是轴对齐的时候,文字的基线会对齐到最近的像素上,这样文字看起来会更清晰。特别是在小字号的情况下,这个设置能显著提升可读性。
嵌入位图:setEmbeddedBitmaps
有些字体文件里嵌入了位图版本的字形,这个设置控制是否使用这些位图:
import { drawing } from '@kit.ArkGraphics2D';
let font : drawing.Font = new drawing.Font();
font.setTypeface(new drawing.Typeface());
font.setEmbeddedBitmaps(false);
console.info("draw isEmbeddedBitmaps: " + font.isEmbeddedBitmaps());
在某些场景下,使用嵌入位图可以获得更好的渲染效果,特别是在小字号时。但大多数情况下,使用矢量轮廓(设置为 false)效果更好。
自动调整轮廓:setForceAutoHinting
这个设置强制对字型轮廓进行自动调整:
import { drawing } from '@kit.ArkGraphics2D';
let font : drawing.Font = new drawing.Font();
font.setTypeface(new drawing.Typeface());
font.setForceAutoHinting(false);
console.info("drawing isForceAutoHinting: " + font.isForceAutoHinting());
即使字体文件里包含了 hinting 信息,开启这个选项后也会使用自动 hinting 算法。这在某些情况下可以获得更一致的渲染效果。
跟随主题字体:setThemeFontFollowed
从 API version 15 开始,Font 支持跟随系统主题字体:
import { drawing } from '@kit.ArkGraphics2D';
let font : drawing.Font = new drawing.Font();
font.setThemeFontFollowed(true);
console.info("font is theme font followed: " + font.isThemeFontFollowed());
开启这个功能后,如果用户在系统设置里切换了主题字体,你的 APP 里的文字也会跟着变。这对需要和系统风格保持一致的应用很有用。
文字绘制的完整流程
在实际开发中,使用 Font 绘制文字的典型流程如下:
小结
Font 类是 HarmonyOS drawing 模块里处理文字渲染的核心工具。通过它你可以:
- 控制字体大小、粗细、倾斜、缩放
- 调整渲染质量(亚像素、边缘效果、hinting)
- 测量文本和字形的宽度、边界
- 把文字转换成路径做高级处理
- 关联字体样式、获取度量信息
记住,Font 使用的是物理像素单位 px,而且是单线程模型,需要你自己管理线程安全。在实际开发中,建议创建一个 Font 对象后重复使用,而不是每次都 new 一个新的。
更多推荐


所有评论(0)