結論
API Level9以降(2.3)ならCaligraphyを使う
chrisjenx/Calligraphy · GitHub
疑問
マテリアルガイドラインによると、RobotoフォントとかNotoフォントを使えって書いたある。 ちょろっと調べて思い浮かんだ疑問
- assetsにファイルサイズ制限なかったっけ?フォントは圧縮するかダウンロードさせるみたいな記事が沢山ある
- TextViewを拡張してコンストラクタでTypeFaceを生成してセットする方法が良く書かれてるけど、ListViewなんか使った日には画面内に生成されるTextView分だけフォント読み込む処理がはしるんです?やだー!
調査してみる
1. assetsにファイルサイズ制限なかったっけ?フォントは圧縮するかダウンロードさせるみたいな記事が沢山ある
assetsにファイルサイズ制限があるのはAPI Level8まで。 ソースコード漁ってもAPI Levet9以降のasste.hにはUNCOMPRESS_DATA_MAXは存在しなかった。
2.TextViewを拡張してコンストラクタでTypeFaceを生成してセットする方法が良く書かれてるけど、ListViewなんか使った日には画面内に生成されるTextView分だけフォント読み込む処理がはしるんです?やだー!
こういうの
この方法は間違ってないし、この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って有名なんですかね?日本じゃ有名じゃないだけなのか、僕が知らないだけなのか・・・もうちょっと情報収集頑張らねば