高级排版:裁剪与动画
Skija 不仅提供了绘制静态文本的强大工具,还能将文本作为几何对象用于裁剪、遮罩和动画。
文本作为裁剪遮罩
要将文本用作遮罩(例如,在字母内部显示图像),不能简单地“裁剪到文本”。相反,必须先将文本转换为 Path。
1. 从文本获取路径
使用 Font.getPath() 获取特定字形的几何轮廓。
java
Font font = new Font(typeface, 100);
short[] glyphs = font.getStringGlyphs("MASK");
// 获取这些字形的路径
// 注意:getPaths 返回路径数组(每个字形一个)
// 通常需要将它们组合或按顺序绘制
Point[] positions = font.getPositions(glyphs, new Point(50, 150)); // 定位文本
Path textPath = new Path();
for (int i = 0; i < glyphs.length; i++) {
Path glyphPath = font.getPath(glyphs[i]);
if (glyphPath != null) {
// 将字形路径偏移到其位置并添加到主路径
glyphPath.transform(Matrix33.makeTranslate(positions[i].getX(), positions[i].getY()));
textPath.addPath(glyphPath);
}
}2. 裁剪画布
获得 Path 后,即可裁剪画布。
java
canvas.save();
canvas.clipPath(textPath);
// 现在绘制图像(或渐变、图案)
// 它将仅出现在字母 "MASK" 内部
canvas.drawImage(myImage, 0, 0);
canvas.restore();文本动画
Skija 通过 TextBlob 提供对字形定位的低级访问,从而实现高性能文本动画。
1. 逐字形动画(波浪文本)
不直接绘制字符串,而是手动计算每个字符的位置。
java
String text = "Wavy Text";
short[] glyphs = font.getStringGlyphs(text);
float[] widths = font.getWidths(glyphs);
// 计算每个字形的位置
Point[] positions = new Point[glyphs.length];
float x = 50;
float time = (System.currentTimeMillis() % 1000) / 1000f; // 0.0 到 1.0
for (int i = 0; i < glyphs.length; i++) {
// 正弦波动画
float yOffset = (float) Math.sin((x / 50.0) + (time * Math.PI * 2)) * 10;
positions[i] = new Point(x, 100 + yOffset);
x += widths[i];
}
// 根据这些显式位置创建 TextBlob
TextBlob blob = TextBlob.makeFromPos(glyphs, positions, font);
// 绘制
canvas.drawTextBlob(blob, 0, 0, paint);2. 路径上的文本(RSXform)
对于沿曲线排列(并旋转以匹配曲线)的文本,使用 RSXform(旋转缩放平移变换)。
java
// 参见 API 中的 'TextBlob.makeFromRSXform'
// 这允许为每个字形独立指定旋转和位置。可变字体
如果拥有可变字体(如 Inter-Variable.ttf),可以平滑地动画化其字重或倾斜度。
java
// 1. 创建 FontVariation 实例
FontVariation weight = new FontVariation("wght", 400 + (float)Math.sin(time) * 300); // 字重 100 到 700
// 2. 从可变基础创建特定 Typeface
Typeface currentFace = variableTypeface.makeClone(weight);
// 3. 创建字体并绘制
Font font = new Font(currentFace, 40);
canvas.drawString("Breathing Text", 50, 50, font, paint);总结
- 裁剪: 转换 文本 -> 字形 -> 路径 ->
canvas.clipPath()。 - 波浪/移动文本: 手动计算
Point[]位置并使用TextBlob.makeFromPos()。 - 路径上的文本: 使用
TextBlob.makeFromRSXform()。 - 字重/样式动画: 使用可变字体和
makeClone(FontVariation)。