ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

androidでTextViewに埋め込みフォントを使う

結論

API Level9以降(2.3)ならCaligraphyを使う

chrisjenx/Calligraphy · GitHub

疑問

マテリアルガイドラインによると、RobotoフォントとかNotoフォントを使えって書いたある。 ちょろっと調べて思い浮かんだ疑問

  1. assetsにファイルサイズ制限なかったっけ?フォントは圧縮するかダウンロードさせるみたいな記事が沢山ある
  2. TextViewを拡張してコンストラクタでTypeFaceを生成してセットする方法が良く書かれてるけど、ListViewなんか使った日には画面内に生成されるTextView分だけフォント読み込む処理がはしるんです?やだー!

調査してみる

1. assetsにファイルサイズ制限なかったっけ?フォントは圧縮するかダウンロードさせるみたいな記事が沢山ある

assetsにファイルサイズ制限があるのはAPI Level8まで。 ソースコード漁ってもAPI Levet9以降のasste.hにはUNCOMPRESS_DATA_MAXは存在しなかった。

2.TextViewを拡張してコンストラクタでTypeFaceを生成してセットする方法が良く書かれてるけど、ListViewなんか使った日には画面内に生成されるTextView分だけフォント読み込む処理がはしるんです?やだー!

こういうの

seesaakyoto.seesaa.net

この方法は間違ってないし、このTextViewが大量に生成されなければ大した問題じゃない。 が、ListViewとかで使ってしまうと大変なことに。いくらViewがリサイクルされると言っても画面内に同時に表示される分はTextViewが作られるので、その分だけassetsからフォントを読み込んでFaceTypeオブジェクトが作られまくってる(多分)。4.4の端末でOOMで落ちたの久しぶり。

できれば一度読み込んだFaceTypeはActivityかApplication辺りでキャッシュしておきたい。 各TextViewではそれらを使いまわすのが理想。っていうか後からTextViewを全部オリジナルのTextViewに書き換えるの面倒くさい。名前空間の宣言すら面倒くさい。

そこでCaligraphy

唸ってたら同僚からこんなこと書いてあるよってQiitのページを教えてもらった。

font - AndroidでNotoフォント・Robotoフォントを使う - Qiita

Caligraphy。そういうのもあるのか。 使い方を見るとすごく簡単そう。何やってるか気になったので簡単にソース読んでみたのでその内容をざっくりまとめます。 使い方は↑のサイトとかCaligraphyのgithub見るといいと思います。

Context生成時にweapしてる

attachBaseContextをオーバーライドして、CalligraphyContextWrapperでcontextをラップしてる。 これはContext.getSystemService()をオーバーライドする為にやっているようだ。 こうすることで、LAYOUT_INFLATER_SERVICEが呼ばれた時に、CalligraphyLayoutInflaterを使用するようになる。

で、どうやってTextViewにFontをセットしてるの?

CalligraphyLayoutInflaterの内部でinflateされるViewがTextViewだった場合にFontがセットされているようです。 また、TypeFaceもActivity毎にキャッシュされているので、ListViewで大量にTextViewが生成されてもロードされるのは1種類につき1回だけですね。

これだ!これを求めたいたのだ!

最悪自分で実装しようと思ってたので、こんだけドンピシャなライブラリがあったのは僥倖でした。 FAQに「カスタムIDを使うのにaarを使う必要があるから、jarでは提供しないよ、っていうかGradleつかってないの?」って書いてある点も個人的にポイント高めです。 「android TextView custom font」とかでググっても出てこなかったのが残念。っていうか古い情報ばっか出てきて混乱した。僕は全然知らなかったんですが、Calligraphyって有名なんですかね?日本じゃ有名じゃないだけなのか、僕が知らないだけなのか・・・もうちょっと情報収集頑張らねば