UITextView:概要、複数行入力、動作原理

著者: IT Sectr 公開日: 2026-07-07 読了時間: 8 分

UITextViewはUIKitの複数行テキストコンポーネントで、UIScrollViewを継承し、リンクや画像を埋め込んだ属性付きテキストの編集をサポートします。Apple Developerドキュメント(2025)によると、UITextViewはtextViewDidChange、shouldInteractWithURL、shouldInteractWithTextAttachmentのコールバックを持つUITextViewDelegateを提供し、インタラクションを処理します。UITextFieldとは異なり、UITextViewはスクロール、typingAttributesによるテキストスタイル、リンクやアドレス、日付を自動検出するdataDetectorTypesをサポートします。これはiOSアプリケーションでコンテンツを表示し、複数行テキストを入力するための主要コンポーネントです。

主要ポイント

  • UITextView — UIKitの複数行テキストフィールド、編集サポート付きUIScrollViewの継承
  • NSAttributedString — 属性付きテキストサポート:フォント、色、行間、リンク
  • UITextViewDelegate — textViewDidChange、shouldInteractWithURL、didBeginEditingによる管理
  • Data Detector Types — テキスト内のリンク、アドレス、日付、電話番号の自動検出
  • Text Container — カスタムレイアウトのためのtextContainer、exclusionPaths、lineFragmentPaddingシステム

UITextViewとは

UITextViewは、複数行テキストの表示と編集のために設計されたUIKitコンポーネントです。UILabelとは異なり、UITextViewはテキスト選択、編集、コンテンツがサイズを超えた場合のスクロール、属性付きテキストをサポートします。UIScrollViewのサブクラスとして、UITextViewはコンテンツがオーバーフローしたときに垂直および水平スクロールを自動的に含めます — これはisScrollEnabledで設定します。このクラスはisEditableプロパティを通じて編集をサポートします:読み取り専用モードの場合はfalseに設定します。UITextViewはTextKitシステムを通じてNSLayoutManagerと連携します:NSTextStorage(属性付きテキストの保存)→ NSLayoutManager(行のレイアウト)→ NSTextContainer(テキスト領域の形状)。このアーキテクチャにより、画像の回り込み、マルチカラムテキスト、複雑なテキストレイアウトを備えたカスタムレイアウトが可能になります。UITextViewはiOSで記事、説明、ログ、コメント、あらゆる複数行テキストの表示に使用されます。

UITextView vs UITextField:主な違い

UITextViewUITextFieldの違いは行数をはるかに超えます。UITextFieldはプレースホルダー、左/右ビュー、クリアボタンを備えた単一行のUIControlです。UITextViewは属性付きテキストのための完全なTextKitシステムを備えた複数行のUIScrollViewです。UITextFieldは表示レベルでNSAttributedStringをサポートしません(制限付きのattributedTextのみ)、UITextViewは異なるフォント、段落スタイル、埋め込み画像でNSAttributedStringを完全に処理します。UITextFieldには組み込みのクリアボタン(clearButtonMode)がありますが、UITextViewにはありません — カスタム実装が必要です。UITextFieldはコンテンツに合わせて自動的にサイズ変更されますが(intrinsicContentSize)、UITextViewはcontentSizeの監視またはAuto Layout制約による手動の高さ管理が必要です。UITextViewはdataDetectorTypesをサポートし、UITextFieldはiOS 16+からサポートします。複数行テキスト入力(コメント、メモ、メッセージ)にはUITextViewを選択してください。フォームフィールド(名前、メール、パスワード)にはUITextFieldを使用してください。

機能UITextViewUITextField
複数行単一行
プレースホルダーなし(カスタム)組み込み
テキスト属性完全なNSAttributedString制限付き
Data Detectors完全サポートiOS 16+
インライン画像NSTextAttachment経由非対応
スクロール組み込み(UIScrollView)なし
左/右ビューなし組み込み

NSAttributedStringとテキスト書式設定

NSAttributedStringはUITextViewの基本的な機能であり、UITextFieldやUILabelと区別するものです。属性付き文字列を使用すると、1つのテキスト内で異なるフォント、色、行間、配置、リンクを設定できます。プロパティ:textView.attributedText = attributedString。主要なNSAttributedString.Key属性:font(.systemFont、.boldSystemFont、カスタムUIFont)、foregroundColor、backgroundColor、paragraphStyle(lineSpacing、alignment、lineBreakModeを持つNSMutableParagraphStyle)、link(インタラクティブリンク用URL)、underlineStyle、strikethroughStyle、shadow、baselineOffset、kern(文字間隔)。attributedStringを作成するにはinit(string:, attributes:)を使用するか、NSMutableAttributedStringを使用して異なる範囲に属性を追加します。UITextViewは自動的にリンク(link属性)をインタラクティブに表示します — 押すとデリゲートメソッドshouldInteractWithURLがトリガーされます。新しい入力の属性をリセットするにはtypingAttributesを使用します。

swift
import UIKit

let textView = UITextView()
textView.isEditable = false
textView.isScrollEnabled = true
textView.dataDetectorTypes = [.link, .phoneNumber]

let attributedString = NSMutableAttributedString(
    string: "Visit our website or call +1-800-555-0199"
)
attributedString.addAttributes([
    .font: UIFont.systemFont(ofSize: 16),
    .foregroundColor: UIColor.label,
], range: NSRange(location: 0, length: 11))

let linkRange = (attributedString.string as NSString)
    .range(of: "website")
attributedString.addAttributes([
    .link: URL(string: "https://example.com")!,
    .foregroundColor: UIColor.systemBlue,
], range: linkRange)

textView.attributedText = attributedString

UITextViewDelegateとリンク処理

UITextViewDelegateは編集とテキストとのインタラクションを管理するプロトコルです。主要メソッド:textViewDidBeginEditing(textView) — 編集開始時に呼ばれます;textViewDidEndEditing — 編集終了時;textViewDidChange — テキスト変更ごと;textViewDidChangeSelection — 選択範囲変更時;textViewShouldInteractWithURL — リンクタップ時(Boolを返し、遷移を許可);textViewShouldInteractWithTextAttachment — 埋め込み画像タップ時。UITextView内のリンクを処理するにはshouldInteractWithURLをオーバーライドします — その中で:SFSafariViewControllerでURLを開く、確認用にUIAlertControllerを表示する、カスタムURLスキームを処理できます。重要:textView.isEditable = trueの場合、リンクはシングルタップで利用できなくなります — ダブルタップが必要です。編集可能なtextViewでインタラクティブなリンクを使用するには、gesture recognizersを使用します。

SFSafariViewControllerによるリンク処理

SFSafariViewControllerはiOSアプリケーションでリンクを開く標準的な方法です。shouldInteractWithURLメソッドでURLを使用してSFSafariViewControllerを作成し、モーダルまたはnavigationControllerを介して表示します。ユニバーサルリンクの場合はUIApplication.shared.open(url, options)を使用します — ただしアプリケーションの外部に出ます。リンクの開始を防ぐにはshouldInteractWithURLでfalseを返し、URLを自分で処理します。

Text Containerシステム:マージンとExclusion Paths

NSTextContainerはTextKitアーキテクチャの一部で、UITextViewテキストが表示される形状領域を定義します。各UITextViewには標準のtextContainerがあり、以下で設定可能です:textView.textContainerInset — textViewの端からのテキストマージン(UIEdgeInsets);textView.textContainer.lineFragmentPadding — 各行内の水平パディング;textView.textContainer.maximumNumberOfLines — 行制限(0 = 制限なし);textView.textContainer.exclusionPaths — テキストが回り込む領域(画像、カスタム形状)のUIBezierPath配列。ExclusionPathsにより複雑なレイアウトが可能になります:テキストが円形のプロフィール画像、アイコン、任意の形状の周りを回り込みます。動的なUITextViewの高さについては、KVOまたはデリゲートを介してcontentSizeを監視し、制約を更新します。

swift
// Dynamic UITextView height via contentSize
func textViewDidChange(textView: UITextView) {
    let fixedWidth = textView.frame.size.width
    let newSize = textView.sizeThatFits(
        CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude)
    )
    heightConstraint.constant = newSize.height
    UIView.animate(withDuration: 0.1) {
        self.view.layoutIfNeeded()
    }
}

// ExclusionPath for image wrapping
let imageFrame = CGRect(x: 16, y: 100, width: 80, height: 80)
let exclusionPath = UIBezierPath(rect: imageFrame)
textView.textContainer.exclusionPaths = [exclusionPath]

Data Detector Types:自動検出

dataDetectorTypesはUITextViewのプロパティで、テキスト内の特定のデータタイプを自動的に認識してインタラクティブにします:.link(URL、メール)、.phoneNumber(電話番号)、.address(住所)、.calendarEvent(日付とイベント)、.flightNumber(フライト番号)、.lookupSuggestion(検索候補)、.trackingNumber(追跡番号)、.money(金額)、.shipmentTrackingNumber、.all(すべてのタイプ)。Data DetectorはNSDataDetectorとURLで動作し、検出されたデータを自動的にハイライトします。処理をカスタマイズするにはdataDetectorTypesを設定し、デリゲートでshouldInteractWithURLをオーバーライドします。重要:dataDetectorTypesは追加設定なしではURLとphoneNumberに対してのみ機能します — 他のタイプにはiOS 16+が必要な場合があります。Data DetectorはNSAttributedStringのlink属性と競合しません — 両方のメカニズムが並行して動作します。コンテンツ(ニュース、記事)を持つ読み取り専用UITextViewの場合は、dataDetectorTypes = [.link, .phoneNumber]を設定します。

  • .link — URL、メールアドレス;青いリンクとして表示
  • .phoneNumber — 電話番号;タップで通話アクションを表示
  • .address — 住所;タップでMapsを開く
  • .calendarEvent — 日付と時刻;タップでカレンダーイベントを作成
  • .flightNumber — フライト番号(iOS 16+);迅速なフライト確認

UITextViewを使用したコード例

iOSアプリケーションでのUITextViewの使用例を2つ見てみましょう。1つ目は、コンテンツ表示のための属性付きテキストとデータ検出器を備えた読み取り専用テキストビュー。2つ目は、コメントフォーム用の遅延プレースホルダーと動的な高さを備えた編集可能テキストビュー。どちらの例もUIKitのベストプラクティス(デリゲートプロトコル、Auto Layout、TextKit)を使用しています。

コンテンツとリンク付き読み取り専用UITextView

読み取り専用モードは、isEditable = falseとisSelectable = trueを設定することで有効になります。これにより、ユーザーはテキストを選択してリンクをタップできますが、編集はできません。リンクの自動検出のためにdataDetectorTypesを設定し、透明な背景のためにbackgroundColor = .clearを設定します。長いコンテンツの場合は、可読性のためにNSMutableParagraphStyle lineSpacing付きのattributedTextを使用します。テキスト内の主要なリンクにlink属性を追加します。

swift
import UIKit

class ArticleViewController: UIViewController {
    let contentView = UITextView()

    override func viewDidLoad() {
        super.viewDidLoad()
        contentView.isEditable = false
        contentView.isSelectable = true
        contentView.dataDetectorTypes = [.link, .phoneNumber]
        contentView.backgroundColor = .clear
        contentView.textContainerInset = UIEdgeInsets(
            top: 8, left: 16,
            bottom: 8, right: 16
        )
        contentView.delegate = self
        loadArticleContent()
    }

    func loadArticleContent() {
        guard let url = URL(string: "https://example.com/article")
        else { return }
        // Load content from URL and set attributedText
    }
}

プレースホルダー付き編集可能UITextView

UITextViewのプレースホルダーは組み込まれていません — textViewの上にUILabelを配置するか、isEmptyチェック付きのattributedTextで実装します。シンプルなアプローチ:編集開始時に非表示になる灰色テキストのUILabel。textViewDidChangeでテキストの有無を確認し、プレースホルダーを表示/非表示にします。よりエレガントな解決策としては、入力テキストの色を設定するためにtypingAttributesプロパティを使用します。動的なtextViewの高さは、contentSizeの監視と制約の更新によって実現されます — これはチャットやコメントフォームの標準パターンです。

よくある質問

UITextViewにプレースホルダーを追加する方法は?

UITextViewには組み込みのプレースホルダーはありません。標準的な解決策:textViewの上に灰色テキストのUILabelを配置します。textViewDidBeginEditingでラベルを非表示にし、textViewDidEndEditingでテキストが空の場合は表示します。代替案:プレースホルダーとして灰色のattributedTextを使用し、編集開始時にリセットします。既成の解決策としては、KMPlaceholderTextViewライブラリまたはReactorKitを使用してください。

UITextViewのマージンを削除する方法は?

textContainerInset = .zeroおよびlineFragmentPadding = 0を設定します:textView.textContainerInset = UIEdgeInsets.zerotextView.textContainer.lineFragmentPadding = 0。さらに:textView.contentInset = .zero。これにより、textViewの端からテキストまでのマージンが完全に削除されます。lineFragmentPaddingのデフォルトは5であることに注意してください。

UITextViewがリンクを開かないのはなぜですか?

確認事項:isSelectable = true(インタラクションに必要)、dataDetectorTypesに.linkが含まれている、デリゲートがshouldInteractWithURLでfalseを返していない。textView.isEditable = trueの場合、リンクはシングルタップで利用不可になります — ダブルタップが必要です。編集可能なtextViewでインタラクティブなリンクを使用するには、textViewの上にUITapGestureRecognizerを追加し、URLを手動で処理します。

スクロール付きの固定高さUITextViewを作成する方法は?

isScrollEnabled = trueを設定し、固定値で高さ制約を追加します。高さを超えるテキストはスクロールされます。最適なUXのためにはmaxHeightを使用します:contentSizeを監視し、高さ制約をmaxHeight以下に設定します。maxHeightを超えたらscrollEnabledを有効にします。これはメッセージ入力フィールドやコメントフォームの標準パターンです。

UITextViewに画像を挿入する方法は?

NSTextAttachmentを使用します:オブジェクトを作成し、画像とboundsを設定し、アタッチメントからNSAttributedStringを作成してtextView.attributedTextに挿入します。例:let attachment = NSTextAttachment();attachment.image = image;attachment.bounds = CGRect(x, y, width, height);let attributedString = NSAttributedString(attachment: attachment)。画像はテキストにインラインで表示され、テキストと一緒にスクロールします。

まとめ

  • UITextView — UIKitの複数行テキストコンポーネント、TextKitサポート付きUIScrollViewの継承
  • NSAttributedString — フォント、色、リンク、段落を書式設定するための主要機能
  • UITextViewDelegate — 編集管理とリンク・添付ファイルタップの処理
  • Data Detector Types — NSDataDetectorによるURL、電話、住所、日付の自動検出
  • Text Container — レイアウトのためのexclusionPaths、lineFragmentPadding、textContainerInsetを持つシステム
  • プレースホルダー — 組み込みでなく、UILabelまたは灰色のattributedTextで実装
  • 動的高さ — 自動高さのためのcontentSize監視と制約更新
  • UITextViewは複数行、属性、スクロール、データ検出のサポートにおいてUITextFieldと異なります

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください