表示されるテキストによって高さを調整する

iPhoneアプリで画面に複数行の文字を表示するにはUILabelかUITextViewを使います。 そのときに、表示するテキストの長さによってテキスト表示エリアの大きさを変えたいことがあります。 NSStringのメソッドを使う方法、NSAttributedStringのメソッドを使う方法、UITextViewのテキスト描画が終わったら微調整する方法、があります。

NSStringのsizeWithFont:constrainedToSize: を使う

NSStringにsizeWithFont:constrainedToSize:というメソッドがあり、指定したフォントでテキスト描画をしたときのサイズを計算することができます。 UILabelとUITextViewで使うことができます。(UITextViewでは微調整する必要があります。)

UILabelとUITextViewに適用したコードはこちら。

UILabelとUITextViewのsizeWithFont:constrainedToSizeを ...

青いUILabelと赤いUITextViewを作成して、長めのテキストを設定。 その後、sizeWithFont:constrainedToSize:でテキストの表示エリアをCGSizeで計算し、その高さをUILabelとUITextViewに設定しています。

ただし、UITextViewはテキスト表示エリアがマージンがあったり、スクロールバーの表示エリアがあったりするので、テキストの表示エリアはUITextViewのframeより少し小さくなってしまいます。 テキスト表示エリアの幅とframeの幅を同じ値にしてしまうと、テキストがちょっとはみでて描画されてしまうんですよね。 (そのため、上のコードでは、UITextViewのframeの幅を200にしましたが、テキスト表示エリアの幅を180にして表示領域の計算を行っています。ただ、この微調整値はiOSのバージョンなどによって違ってくる可能性もあるので、あまり固定値にはできませんね……。)

描画エリアを明確にしたいのなら、UITextViewは避けた方がよさそうです。 (使うのなら、多少余白がでてもいいように調整したほうがいいですね。)

上のコードを動かすとこんな感じになります。 青いUILabelも赤いUITextViewもテキストの内容にあわせて高さが変わっています。 TextSize1

NSAttributedStringのboundingRectWithSize:options:attributes:context: を使う

次は、NSAttributedStringのboundingRectWithSize:options:attributes:context:メソッドを使う方法。 こちらはiOS6.0以降でのみ利用可能ですが、Apple的にはNSStringよりもこちらが推奨のようです。 これもUILabelとUITextViewで使うことができます。(UITextViewでは同様に微調整する必要があります。)

UILabelとUITextViewのコードはこちら。

NSAttributedStringのboundingRectWithSize:options:at ...

ただし、UITextViewのマージンがさらに大きくなったので、そのあたりの微調整が面倒くさそう。 (下の画面キャプチャーでも文字がちょっとはみでています。)

TextSize2

UITextViewのテキスト描画が終わったら微調整

最後はUITextViewだけで使える方法です。 UITextViewの親クラスはUIScrollViewなんですが、そのUIScrollViewは内部に大きいサイズのViewを入れてスクロールして表示しています。 その内部ViewのサイズがcontentSizeとしてとれるので、それをframeに設定すればテキストにあわせてframeが設定できます。

ただし、テキストのレンダリング処理が終了してないと適切なcontentSizeはとれないので、タイミングによっては意図通りに動きません。

テキストの描画処理が終わった段階で下記のコードをよべば、内部の大きさにあわせてUITextViewの大きさが変更できます。 UITextViewを使うのならこれが確実ですね。

UITextViewのテキスト描画が終わったら微調整してサイズを変更する方法(http://ww ...

まとめ

表示するテキストをユーザーが変更する必要がないなら、UILabel+NSAttributedStringを使うのがベスト。 変更する必要があるなら、UITextViewを使って変更が終わった段階でcontentSizeで調整するのがよさそうですね。