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

Text Kitによるテキストレイアウト(前編)(2ページ目)

これらのクラス関係の例を下図に示します(図16)。この例は、テキストストレージが持つテキストコンテンツを、2ページ(もしくは2カラム)に分割して表示する場合のクラス関連図です。そのため、レイアウトマネージャが2つ存在しています。

図16: Text Kitのクラス関係(複数ページに分割表示する例)

UITextViewのインスタンスを生成すると、そのUITextViewに関連付けされたNSTextContainer、NSLayoutManager、NSTextStorageのインスタンスが生成され、プロパティを通してアクセス可能となります。ただし、これらのプロパティはreadonlyであるため、生成後に変更することはできません。
テキストビューに自前のテキストコンテナを対応付けるには、以下のメソッドを利用してコードからUITextViewのインスタンスを生成します。

[ソースコード39] 自前のテキストコンテナを持つUITextViewを生成するメソッド

- (instancetype)initWithFrame:(CGRect)frame
                textContainer:(NSTextContainer *)textContainer;

レイアウトマネージャを利用すると、位置座標から表示されている文字を取得することが可能です。これをヒットテストと呼びます。例えば、タップ位置(タッチ終了位置)に表示されている文字は、下記のコードで取得できます。

[ソースコード40] 座標から文字インデックスを取得(ヒットテスト)

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint locationInView = [touch locationInView:self.textView];
  
    NSTextContainer *textContainer = self.textView.textContainer;
    NSLayoutManager *layoutManager = self.textView.layoutManager;
    // テキストコンテナの座標系に変換
    CGPoint locationInContainer =
    CGPointMake(locationInView.x - self.textView.textContainerInset.left,
                locationInView.y - self.textView.textContainerInset.top);
    // 文字インデックスを取得
    NSUInteger charIndex = [layoutManager characterIndexForPoint:locationInContainer
                                                 inTextContainer:textContainer
  fractionOfDistanceBetweenInsertionPoints:NULL];

  // テキストストレージから該当文字を取得
  NSString *charString =
  [[self.textView.textStorage string] substringWithRange:NSMakeRange(charIndex, 1)];
}

上記の処理内容はシンプルです。まずtextViewの座標系におけるタッチ位置を取得します。得られた位置をテキストコンテナの座標系に変換します。このとき、UITextViewが持つtextContainerInsetプロパティの値を用います。テキストコンテナの座標系でのタッチ位置が得られたら、あとはそこから文字インデックスを取得できます。

この記事のキーワード

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る