テキストの応用
グリフを直接並べるGlyphs、パスに沿わせるTextPath、事前計算済みのTextBlobといった、低レベルなテキストAPIを解説します。
文字列をそのまま置くか、段落として組むか、グリフ単位で位置を制御するかでAPIを選びます。
前章の<Text>や<Paragraph>は「文字列を渡せばレイアウトしてくれる」高レベルなAPIでした。この章で扱うのは、グリフ(フォント内の個々の字形)の位置を自分で計算して並べる、より低レベルなAPI群です。曲線に沿ったテキストや、縦書き風の配置、パフォーマンスが重要な場面での再利用可能な描画データが必要なときに使います。
Glyphs: グリフを直接並べる
<Glyphs>は、グリフIDと位置の配列を受け取ってそのまま描画するコンポーネントです。<Text>のような自動レイアウトは行わず、1文字ずつの位置を完全にコントロールできます。
| Name | Type | Description |
|---|---|---|
| glyphs | Glyph[] |
描画するグリフの配列({ id, pos }) |
| font | SkFont |
使用するフォント |
| x? | number |
全体の原点のx座標(デフォルトは0) |
| y? | number |
全体の原点のy座標(デフォルトは0) |
文字列からグリフIDの配列を得るには、フォントのgetGlyphIDs(text)を使います。以下は各文字を縦に並べる例です。
import { Canvas, Glyphs, vec, useFont } from "@shopify/react-native-skia";
const HelloWorld = () => {
const fontSize = 32;
const font = useFont(require("./assets/my-font.ttf"), fontSize);
if (!font) {
return null;
}
const glyphs = font
.getGlyphIDs("Hello World!")
.map((id, i) => ({ id, pos: vec(0, (i + 1) * fontSize) }));
return (
<Canvas style={{ flex: 1 }}>
<Glyphs font={font} glyphs={glyphs} />
</Canvas>
);
};
以下のデモは同じ考え方で日本語の文字を1文字ずつ縦に並べたものです。posをvec(x, y)で自由に計算できるので、螺旋状に配置したり間隔を不均一にしたりといった表現も同じ仕組みで作れます。
TextPath: パスに沿ってテキストを描く
<TextPath>はテキストを指定したパスに沿わせて描画します。パスはSkia.PathBuilderで作ったオブジェクトのほか、SVGパス記法の文字列でも指定できます。
| Name | Type | Description |
|---|---|---|
| path | Path または string |
テキストを沿わせるパス |
| text | string |
描画する文字列 |
| font | SkFont |
使用するフォント |
| initialOffset? | number |
パス上での開始位置のオフセット |
import { Canvas, Group, TextPath, Skia, useFont, vec, Fill } from "@shopify/react-native-skia";
const size = 128;
const path = Skia.Path.Circle(size, size, size / 2);
const HelloWorld = () => {
const font = useFont(require("./assets/my-font.ttf"), 24);
return (
<Canvas style={{ flex: 1 }}>
<Fill color="white" />
{font && (
<Group transform={[{ rotate: Math.PI }]} origin={vec(size, size)}>
<TextPath font={font} path={path} text="Hello World!" />
</Group>
)}
</Canvas>
);
};
以下のデモでは、日本語テキストを円形のパスに沿わせています。rotationを動かすと、<Group>のtransformでパスごとテキストが回転する様子が確認できます。
TextBlob: 事前計算済みのテキストデータ
TextBlobは、グリフ・位置・フォント情報をひとまとめにした不変(immutable)のデータです。Skia.TextBlob.MakeFromTextで文字列とフォントから作成し、<TextBlob>で描画します。
| Name | Type | Description |
|---|---|---|
| blob | TextBlob |
描画するTextBlob |
| x? | number |
原点のx座標(デフォルトは0) |
| y? | number |
原点のy座標(デフォルトは0) |
import { Canvas, TextBlob, Skia, useFont } from "@shopify/react-native-skia";
const HelloWorld = () => {
const font = useFont(require("./assets/my-font.ttf"), 24);
if (!font) {
return null;
}
const blob = Skia.TextBlob.MakeFromText("Hello World!", font);
return (
<Canvas style={{ flex: 1 }}>
<TextBlob blob={blob} color="blue" />
</Canvas>
);
};
<Text>との違いは、レイアウト計算(グリフの並べ方の決定)をMakeFromTextの時点で1回だけ行い、その結果をTextBlobとして保持する点です。同じテキストを毎フレーム描画するアニメーションなどでは、<Text>が内部で行っている計算を省略できるため、わずかながら有利になります。実用上は<Text>で十分なことがほとんどなので、パフォーマンス計測で差が問題になった場合の選択肢として覚えておく程度でよいでしょう。
以下のデモはfontSizeと色相を変えられる、TextBlobを使ったシンプルな例です。
どのAPIを選ぶか
- 通常のUI文字列やボタンのラベルなど、素直な1行テキストには
<Text> - 複数行・複数スタイル・折り返しが必要なら
<Paragraph> - グリフ単位で位置を完全にコントロールしたい特殊な配置には
<Glyphs> - テキストを曲線に沿わせたい場合は
<TextPath> - 同じテキストを繰り返し描画するホットパスでの微調整には
<TextBlob>
低レベルなAPIほど、フォントのメトリクスやグリフIDの扱いなど自分で面倒を見る範囲が広がります。まずは<Text>と<Paragraph>で足りるかを検討し、それでも表現できない配置が必要になったときにこの章のAPI群を思い出してください。