ラベル UIKit Additions の投稿を表示しています。 すべての投稿を表示
ラベル UIKit Additions の投稿を表示しています。 すべての投稿を表示

2012年9月14日金曜日

NSString UIKit Additions のバグ

NSString UIKit AdditionsにあるsizeWithFont:は、文字列を指定フォントで表示した時の表示サイズを求めるメソッドとされている。


ところがこれ、横幅は正しいのだが、縦幅は正しくないことがある。
表示幅が取得値(size.height)より大きいことがあるのだ。

どのような場合にそうなるか。


指定フォントが英字フォントで、文字列に日本語を含む場合がそれに当たる。

この場合、英字部分は指定フォントが使われるが、日本語に関しては代替フォントが使われる。
例えば、標準的フォントとしてよく使われるHelveticaは英字フォントであり、実は日本語は含まない。それでも日本語も表示できるのは、この代替機能があるからだ。絵文字もこの機能によって、どのフォントでも表示できるようになっている。
(フォントが実際のところどの文字コードに相当するフォントを持っているかは、FontBookで情報を見ると分る。)

そして、殆どの場合その代替フォントのほうが大きいので、高さがそちらに合わせられる。
このため、実表示サイズが取得値と合わなくなる。

 sizeWithFontが返してくるのは指定したフォントのlineHeightであり、文字列に含まれるすべての文字を考慮した高さではないのだ。

その代替となっている日本語フォントのlineHeightを得ておけばいいと思うかもしれないが、それがそう単純ではなく、実際に表示される文字だけのフォント幅に合わせられる。
よって、表示文字列が固定ならいいが、文字列が可変なら高さも可変になる。

ということで、現在出来る回避策は、実際に表示させてみるしかない。
例えばUITextView.textに「改行付きで」代入し、その前後でcontentSize.heightの
差分を取る。これなら正確に取得できる。
ただし、.textへの代入の処理はかなり重いので、すべての行の高さを得ようと思うなら、ちょっと工夫が必要である。


アップルは英語圏なので、こういう日英文字混在の条件下ではデバッグされていないのだろう。iOS5.1でも治っていない。iOS6でどうかは未検証。


2012/09/25追記
drawAtPointの返してくる高さも同様と判明。横幅はなぜかちょっと違う。
sizeWithFontの方が小数点以下を切り上げた幅を返してきている感じ。

あと、ひょっとしたらこの問題はUITextView内に表示した時だけに発生するのかもしれない。UITextViewないならフォントの高さなんて気にしなくていいのではないかと思われるかもしれないが、外部表示との同期をかけようとすると問題になる。
それがどういうことかは、次回アプリを見てもらえばわかるかと。

2013/09/29追記
1年ぶりの追記。実はiOS7では contentSize.heightの返す値が全く意味不明になっておりこの方法が使えなくなってしまった。現状回避策は見つかってない。