🦔

UITextViewとNSRangeを組み合わせたテキスト操作入門 ✍️📄📱

に公開

UITextViewとNSRangeを組み合わせることで、テキストの選択や検索、装飾、スクロール制御など、さまざまな機能を実装できます。本記事では、UIKitのUITextViewを使った基本的なNSRangeの仕組みから応用例まで解説します。🔍✨🎨


はじめに 🎯🔰💡

  • 対象読者:UITextViewを利用したテキスト操作を学びたい人
  • 目的:NSRangeの基本を理解し、UITextViewでの選択制御やハイライト、スクロール制御などを実装できるようになる

📚 参考資料:


1. NSRangeの基本 📐🔢🔍

NSRangeは、配列や文字列の一部分を指定するために使う構造体で、location(開始位置)とlength(要素数)の2つの値を持ちます。たとえば文字列の5文字目から10文字分を扱いたいときに使います。📝📏📚

// C言語定義
struct _NSRange {
    NSUInteger location;
    NSUInteger length;
};
typedef struct _NSRange NSRange;
  • NSNotFound:検索結果が見つからなかったときの値
  • NSMakeRange(loc, len):開始位置locと長さlenで範囲を作成
  • NSMaxRange(range)location + lengthで範囲の終わりを取得
  • NSLocationInRange(pos, range):位置posrangeの中にあるか判定
  • NSStringFromRangeNSRangeFromString:範囲を文字列に変換/文字列から範囲に変換

関連クラス 💼🏷️📦

以下のクラスでNSRangeが使われる場面をまとめました。

クラス名 用途
NSString 不変文字列の部分抽出・検索
NSMutableString 文字列の挿入・削除時の範囲指定
NSArray 不変配列の部分抽出
NSMutableArray 配列の要素追加・削除の範囲操作
NSAttributedString 装飾文字列の属性適用範囲
NSMutableAttributedString 属性の追加・変更範囲
NSTextStorage テキストと属性の管理、編集範囲の通知
NSLayoutManager レイアウトや描画時のグリフ範囲
NSTextContainer テキストの描画領域設定

2. UITextViewとNSRangeの組み合わせ 📲✏️🔧

2.1 テキスト選択の制御 🔲✅👆

アプリから任意の範囲を選択状態にできます。以下は開始位置5、長さ10の範囲を選択する例です。

let textView = UITextView()
let startIndex = 5
let selectionLength = 10
textView.selectedRange = NSMakeRange(startIndex, selectionLength)
  • selectedRangeを設定するだけで選択できる
  • textViewDidChangeSelection(_:)で選択範囲変更を検知可能

📚 UITextViewDelegate.textViewDidChangeSelection(_:) — Apple Developer

2.2 検索ワードのハイライト 🔎✨🖍

正規表現で見つけた範囲を背景色でハイライトする例です。

let text = textView.text ?? ""
let attributed = NSMutableAttributedString(string: text)
let regex = try! NSRegularExpression(pattern: "重要キーワード")
let matches = regex.matches(
    in: text,
    range: NSMakeRange(0, text.utf16.count)
)
matches.forEach { match in
    attributed.addAttribute(
        .backgroundColor,
        value: UIColor.yellow,
        range: match.range
    )
}
textView.attributedText = attributed

📚 NSRegularExpression — Apple Developer

2.3 スクロールによるフォーカス移動 📜⬇️📍

指定した位置まで自動でスクロールします。

textView.scrollRangeToVisible(NSMakeRange(50, 0))
  • 長い文章の中で特定箇所をユーザーに見せたいときに便利

📚 UITextView.scrollRangeToVisible(_:) — Apple Developer


3. UIFontTextViewの内部構造とNSRange応用 🏗️🔍🔄

UITextViewは以下のコンポーネントでテキスト編集機能を実現しています。

  1. NSTextStorage
  2. NSLayoutManager
  3. NSTextContainer

3.1 NSTextStorage 📦📝⚙️

テキストと属性を管理し、変更時にNSRangeで編集範囲を通知します。

class HighlightTextStorage: NSTextStorage {
    private let storage = NSMutableAttributedString()
    override var string: String { storage.string }
    override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key : Any] {
        storage.attributes(at: location, effectiveRange: range)
    }
    override func replaceCharacters(in range: NSRange, with str: String) {
        beginEditing()
        storage.replaceCharacters(in: range, with: str)
        edited([.editedCharacters, .editedAttributes], range: range, changeInLength: (str as NSString).length - range.length)
        endEditing()
    }
    override func setAttributes(_ attrs: [NSAttributedString.Key : Any], range: NSRange) {
        beginEditing()
        storage.setAttributes(attrs, range: range)
        edited(.editedAttributes, range: range, changeInLength: 0)
        endEditing()
    }
}

📚 NSTextStorage — Apple Developer

3.2 NSLayoutManager 🖼️🔲📐

グリフ単位のレイアウト情報をNSRangeで扱い、カスタム描画に活用できます。

let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: textView.bounds.size)
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
let glyphRange = NSMakeRange(10, 5)
layoutManager.enumerateLineFragments(forGlyphRange: glyphRange) { rect, _, _, _, _ in
    // カスタム描画
}

📚 NSLayoutManager — Apple Developer

3.3 NSTextContainer 📐🗺️🔧

描画領域のサイズや余白を設定し、テキストの折り返しを制御します。

let textContainer = NSTextContainer()
textContainer.lineFragmentPadding = 5
textContainer.size = CGSize(width: textView.bounds.width, height: .greatestFiniteMagnitude)

📚 NSTextContainer — Apple Developer


4. まとめ 🏁📌🎉

  • NSRangeUITextViewを組み合わせることで、選択操作、ハイライト、スクロール制御など多彩なテキスト機能を実装できる
  • NSTextStorage/NSLayoutManager/NSTextContainerの連携を理解すると、さらに高度なカスタマイズが可能になる
  • まずは基本のAPIを試し、次に内部コンポーネントを活用してリッチなテキスト機能を作り込もう🚀

以上の内容を参考に、自分のアプリや学習プロジェクトで実践してみてください!


📅 参考文献

Discussion