Text Kitによるテキストレイアウト(後編)

2014年10月21日(火)
西方 夏子(にしかた・なつこ)

テキストコンテナの生成は、次のプライベートメソッドにより行います。

[ソースコード45] テキストコンテナの生成

- (void)createContainers
{
  // 最終コンテナに含まれるグリフ範囲を示す
  NSRange range = NSMakeRange(0, 0);
  
  // 最終コンテナに含まれるグリフインデックスの最大値と
  // レイアウトマネージャが持つグリフ数を比較
  while (NSMaxRange(range) < self.layoutManager.numberOfGlyphs) {
      // テキストコンテナの生成
      NSTextContainer *container =
      [[NSTextContainer alloc] initWithSize:self.containerSize];
      // レイアウトマネージャにテキストコンテナを追加
      [self.layoutManager addTextContainer:container];
      // 作成したテキストコンテナに含まれるグリフ範囲を取得
      // →ループの条件判断に戻る
      range = [self.layoutManager glyphRangeForTextContainer:container];
  }
}

上記コードでは、テキストコンテナを作成してレイアウトマネージャに追加する処理を繰り返しています。十分な数のコンテナを作成できたかは、グリフ数(文字数とは異なるテキストコンテンツの長さ)を元に判断します。
レイアウトマネージャにテキストコンテナを追加したら、そのコンテナに含まれるグリフの範囲を取得します。グリフ範囲の最大インデックスは、それまでに作成したコンテナに格納されるグリフ数を意味します。したがって、このグリフインデックスとレイアウトマネージャが持つグリフ数(全テキストコンテンツを示す)を比較すれば、コンテナ数が十分であるか判断できます。レイアウトマネージャが持つグリフ数が大きければ、コンテナ数が不足しているので、さらにコンテナを作り続けます。
これで、必要な数のテキストコンテナを生成することができます。
なお、ここではcontainerSizeはreadonlyとして、初期化時に指定していますが、動的にコンテナサイズの変更が必要になる場合は適宜置き換えてください。
例えば、デバイスの回転でテキストビューのサイズが変更になるケースでは、コンテナサイズも変更する必要があります。コンテナサイズが変更されたら、レイアウトマネージャが持つテキストコンテナも生成し直す必要があります。また、表示コンテンツとなるtextStorageが変更になった場合も同様に、コンテナの再生成が必要となります。

最後に、TextModelを使用したUITextViewの作成例を示します。
テキストコンテンツを表示するには、UITextViewを生成する際にTextModelが管理するレイアウトマネージャからテキストコンテナを取得し、テキストビューと対応付ければ該当ページのUITextViewが作成できます。
例えば、1ページ目(ページインデックス0)を表示するUITextViewの生成は、下記の通りです(ソースコード9.46)。

[ソースコード46] UITextViewの生成

CGRect textViewRect = ...;
CGSize textViewSize = textViewRect.size;
UIEdgeInsets containerInset = UIEdgeInsetsMake(10, 10, 10, 10);
CGSize containerSize = 
CGSizeMake(textViewSize.width - containerInset.left - containerInset.right,
           textViewSize.height - containerInset.top - containerInset.bottom);
  
self.model = [[TextModel alloc] initWithContainerSize:containerSize];

// ページインデックス0のテキストコンテナを取得
NSTextContainer *textContainer = self.model.layoutManager.textContainers[0];
// テキストコンテナを指定してUITextViewを生成
UITextView *textView = [[UITextView alloc] initWithFrame:textViewRect 
                                           textContainer:textContainer];
textView.textContainerInset = containerInset;

なお、既に説明した通り、テキストコンテナはUITextViewの生成時にしか設定できません。StoryboardなどでUITextViewを配置する場合は、独自のテキストコンテナは使用できないので注意してください。

この記事のもとになった書籍
UIKit徹底解説 iOSユーザーインターフェイスの開発

西方 夏子 著/丸山 弘詩 編
価格:3,800円+税
発売日:2014年06月13日発売
ISBN:978-4-8443-3608-2
発行:インプレスジャパン

UIKit徹底解説 iOSユーザーインターフェイスの開発

ユーザーインターフェイス(UI)を制御するUIKitは、iOSアプリの中心的役割を担います。UIKitを深く理解することが、アプリ開発での多くの問題解決に繋がります。本書では、アプリの起動から画面表示、画面レイアウト、イベントハンドリングと、常に稼働しているUIKitの機能を丁寧に解説します。メインとなるコンテンツの表示からステータスバーを含むバーの制御、フォントやテキストの改良など、ビューやテキストの「外観」(アピアランス)を改善する内容も充実させています。使用頻度の高いテーブルビューとコレクションビュー、そしてユニバーサルアプリ化に有益なカスタムコンテナビューコントローラに関しては、チュートリアル形式で解説します。また、StoryboardやAuto Layoutも今後のアプリ開発でさらに重要となる状況を見越して、詳細解説に留まらず同じくチュートリアルで多くの具体例を紹介します。

Amazon詳細ページへImpress詳細ページへ

著者
西方 夏子(にしかた・なつこ)

ソフトウェアエンジニア。大手電機メーカーにおける組込みソフトウェアの開発を経て、現在は個人でiOS向けのアプリケーションを開発している。代表作であるローン計算アプリ「iLoan Calc」は、個人の方のみならず、多くの不動産業、金融業の方からも愛用されている。『iPhoneアプリ開発エキスパートガイド iOS6対応』(共著・インプレスジャパン刊)、『上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編』(共著・インプレスジャパン刊)などの執筆にも携わり、現在は執筆業を中心にアプリ開発と育児を両立中。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています