🔥

Jetpack Compose で autoSizeText を実装する

2023/12/14に公開

Jetpack Compose における autoSizeText は、Jetpack Compose Roadmap では現在 In Focus となっていますが、 TextMeasurer を用いることで実装可能です。

やりたいこと

  • テキストのフォントサイズをレイアウトに合わせて調整する
  • 表示・パフォーマンスも気にする

環境

  • Kotlin: 1.9.21
  • Compose Compiler: 1.5.6
  • Compose BoM: 2023.10.01

まずはナイーブに実装してみる

単純には、フォントサイズを remember しておいて、適宜調整すれば表示はできそうです。

しかし実際に実装してみると、以下のようにアニメーションしているように表示されます。

naive_sample

また Recomposition もフォントサイズが変わるたびに発生します。
今回のケースでは表示ボタンを押してから表示が止まるまでに 170 回以上も Recomposition が走っていました。

表示・パフォーマンスも気にして実装する

上記の問題を解決するには、表示前に一気にフォントサイズを求めてあげる必要があります。
JetpackCompose において、テキストを実際に表示することなくレイアウトの計算を行うのに TextMeasurer を使うことができます。

TextMeasurerrememberTextMeasurer() で取得でき、measure() でレイアウト計算に用いる TextLayoutResult を取得できます。

最適なフォントサイズを求める際、先の実装のように順に確かめるよりも TextView で実装されている ように二分探索でやるとより高速に処理できます。

measure() には layout Modifier でおなじみの Constraints が必要となりますが、BoxWithConstraints を使うことで簡単に取得できます。

ナイーブな実装との比較は以下のようになり、即座に表示が完了するほか、Recomposition も発生していませんでした。

compare
recomposition_count

おわりに

TextMeasurer を使うことで Recomposition を繰り返すことなく最適なフォントサイズを求めることができました。
measure() は他にも Text composable の引数にあるような設定値を受け取るため、より細かい指定も可能です。

コード全体は以下から確認できます。

https://gist.github.com/warahiko/573748442a331a6244853570f0abe755

Discussion