跳到主要内容

自定义文本绘制与显示(ArkTS)

在复杂的文本排版场景中,当系统提供的标准文本组件无法满足特定的视觉或交互需求时,开发者可以利用ArkGraphics 2D提供的底层文本绘制能力,通过直接控制画布(Canvas)和文本样式,实现对文本外观、布局的精细控制。这种能力适用于需要高度定制化文本渲染效果的场景,例如艺术字体、复杂的富文本编排或特殊的动态文字效果。

字体引擎作为图形系统中的核心组件,负责将字符代码转换为可视化的字形,并精确计算每个字形的布局和位置,为自定义文本绘制提供底层支持。通过文本测量接口,开发者可以获取文本的精确尺寸,这是实现精准布局(如居中显示)的基础。

文本塑形

场景介绍

文本塑形是字体引擎提供的一项关键能力,它允许开发者不经过系统默认的文本排版流程,直接获取文本的底层字形信息(如宽度、方向等测量信息)。这使得开发者能够基于这些原始数据,实现完全自定义的排版逻辑、绘制操作以及断行策略。

这种能力适用于以下场景:

  • 自定义富文本渲染:例如在社交媒体、新闻客户端等应用中,需要实现图文混排、多样式文本混合显示。
  • 跨平台一致性排版需求应用:确保文本在不同平台或设备上呈现一致的视觉效果。
  • 精细化排版管理:如实现艺术排版、动态文字布局等系统标准文本组件难以达到的效果。

接口说明

文本塑形中常用接口如下表所示,详细接口说明参考@ohos.graphics.text (文本模块)@ohos.graphics.drawing (drawing TextBlob)

接口名描述
buildLineTypeset(): LineTypeset构建行排版器。
createLine(startIndex: number, count: number): TextLine根据指定的排版区间生成文本行对象。
getGlyphRuns(): Array<Run>获取文本行的排版单元数组。
getGlyphs(): Array<number>获取该排版单元中每个字符的字形序号。
getFont(): drawing.Font获取排版单元的字体属性对象。
getAdvances(range: Range): Array<common2D.Point>获取该排版单元指定范围内每个字形的字形宽度数组。
static makeFromRunBuffer(pos: Array<TextBlobRunBuffer>, font: Font, bounds?: common2D.Rect): TextBlob基于RunBuffer信息创建TextBlob对象。
static makeFromRunBuffer(pos: Array<TextBlobRunBuffer>, font: Font, bounds?: common2D.Rect): TextBlob基于RunBuffer信息创建TextBlob对象。
drawTextBlob(blob: TextBlob, x: number, y: number): void绘制一段文字。若构造blob的字体不支持待绘制字符,则该部分字符无法绘制。

开发步骤

从API version 18开始,支持获取文字塑形结果能力。从API version 20开始,支持获取文字排版方向和文字字形宽度。关键代码如下:

  1. 导入依赖的相关模块。

    import { text } from '@kit.ArkGraphics2D'
    import { drawing } from '@kit.ArkGraphics2D'
    import { common2D } from '@kit.ArkGraphics2D'
  2. 创建段落样式,并使用构造段落生成器ParagraphBuilder生成段落实例。

    let myTextStyle: text.TextStyle = {
    // 文本大小
    fontSize: 60
    };
    let myParagraphStyle: text.ParagraphStyle = {
    textStyle: myTextStyle,
    };
    let fontCollection = text.FontCollection.getGlobalInstance();
    let paragraphBuilder = new text.ParagraphBuilder(myParagraphStyle, fontCollection);
  3. 添加文本内容。

    paragraphBuilder.addText('Hello World');
  4. 创建行对象。获取行中所有文字的塑形结果。

    使用createLine()方法创建一个单行对象,通过行对象getGlyphRuns()方法获取相同样式的文字单元。

    // 生成行
    let lineTypeSet: text.LineTypeset = paragraphBuilder.buildLineTypeset()
    let textLine: text.TextLine = lineTypeSet.createLine(0, 11);

    // 获取塑形结果
    let runs: text.Run[] = textLine.getGlyphRuns();
  5. 该步骤是文本塑形流程中的自定义绘制环节。通过调用getGlyphs()方法获取文本中每个字符对应的字形序号,再结合getFont()方法获取的字体对象,即可唯一确定每个字形的具体图形信息。

    从 API version 20 开始,新增的getAdvances()方法能够返回一个数组,其中包含了每个字形在绘制时建议占用的宽度和高度。依赖这些精确的测量数据,开发者可以自由地计算并定义每个字形的绘制位置,从而实现复杂的文本布局效果,如自定义字符间距、垂直偏移或特殊排版。

    let x: number = 0;
    let y: number = 0;
    for (let index = 0; index < runs.length; index++) {
    const run = runs[index];
    // 绘制字形
    let glyphs: number[] = run.getGlyphs();
    let font: drawing.Font = run.getFont();
    let advances: common2D.Point[] = run.getAdvances({ start: 0, end: 0 });

    // 创建字形buffer,通过drawing接口进行字形独立绘制
    let runBuffer: drawing.TextBlobRunBuffer[] = [];
    for (let i = 0; i < glyphs.length; i++) {
    runBuffer.push({ glyph: glyphs[i], positionX: x, positionY: y });
    x += advances[i].x + 10;
    y += advances[i].y + 30;
    }
    let textBlob: drawing.TextBlob = drawing.TextBlob.makeFromRunBuffer(runBuffer, font, null);
    // 自定义绘制一串具有相同属性的一系列连续字形
    canvas.drawTextBlob(textBlob, 20, 100);
    }

效果展示: