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

テキストコンテナの生成は、次のプライベートメソッドにより行います。
[ソースコード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を配置する場合は、独自のテキストコンテナは使用できないので注意してください。



