UITextViewはUIKitの複数行テキストコンポーネントで、UIScrollViewを継承し、リンクや画像を埋め込んだ属性付きテキストの編集をサポートします。Apple Developerドキュメント(2025)によると、UITextViewはtextViewDidChange、shouldInteractWithURL、shouldInteractWithTextAttachmentのコールバックを持つUITextViewDelegateを提供し、インタラクションを処理します。UITextFieldとは異なり、UITextViewはスクロール、typingAttributesによるテキストスタイル、リンクやアドレス、日付を自動検出するdataDetectorTypesをサポートします。これはiOSアプリケーションでコンテンツを表示し、複数行テキストを入力するための主要コンポーネントです。
主要ポイント
UITextViewは、複数行テキストの表示と編集のために設計されたUIKitコンポーネントです。UILabelとは異なり、UITextViewはテキスト選択、編集、コンテンツがサイズを超えた場合のスクロール、属性付きテキストをサポートします。UIScrollViewのサブクラスとして、UITextViewはコンテンツがオーバーフローしたときに垂直および水平スクロールを自動的に含めます — これはisScrollEnabledで設定します。このクラスはisEditableプロパティを通じて編集をサポートします:読み取り専用モードの場合はfalseに設定します。UITextViewはTextKitシステムを通じてNSLayoutManagerと連携します:NSTextStorage(属性付きテキストの保存)→ NSLayoutManager(行のレイアウト)→ NSTextContainer(テキスト領域の形状)。このアーキテクチャにより、画像の回り込み、マルチカラムテキスト、複雑なテキストレイアウトを備えたカスタムレイアウトが可能になります。UITextViewはiOSで記事、説明、ログ、コメント、あらゆる複数行テキストの表示に使用されます。
UITextViewとUITextFieldの違いは行数をはるかに超えます。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を使用してください。
| 機能 | UITextView | UITextField |
|---|---|---|
| 行 | 複数行 | 単一行 |
| プレースホルダー | なし(カスタム) | 組み込み |
| テキスト属性 | 完全なNSAttributedString | 制限付き |
| Data Detectors | 完全サポート | iOS 16+ |
| インライン画像 | NSTextAttachment経由 | 非対応 |
| スクロール | 組み込み(UIScrollView) | なし |
| 左/右ビュー | なし | 組み込み |
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を使用します。
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は編集とテキストとのインタラクションを管理するプロトコルです。主要メソッド:textViewDidBeginEditing(textView) — 編集開始時に呼ばれます;textViewDidEndEditing — 編集終了時;textViewDidChange — テキスト変更ごと;textViewDidChangeSelection — 選択範囲変更時;textViewShouldInteractWithURL — リンクタップ時(Boolを返し、遷移を許可);textViewShouldInteractWithTextAttachment — 埋め込み画像タップ時。UITextView内のリンクを処理するにはshouldInteractWithURLをオーバーライドします — その中で:SFSafariViewControllerでURLを開く、確認用にUIAlertControllerを表示する、カスタムURLスキームを処理できます。重要:textView.isEditable = trueの場合、リンクはシングルタップで利用できなくなります — ダブルタップが必要です。編集可能なtextViewでインタラクティブなリンクを使用するには、gesture recognizersを使用します。
SFSafariViewControllerはiOSアプリケーションでリンクを開く標準的な方法です。shouldInteractWithURLメソッドでURLを使用してSFSafariViewControllerを作成し、モーダルまたはnavigationControllerを介して表示します。ユニバーサルリンクの場合はUIApplication.shared.open(url, options)を使用します — ただしアプリケーションの外部に出ます。リンクの開始を防ぐにはshouldInteractWithURLでfalseを返し、URLを自分で処理します。
NSTextContainerはTextKitアーキテクチャの一部で、UITextViewテキストが表示される形状領域を定義します。各UITextViewには標準のtextContainerがあり、以下で設定可能です:textView.textContainerInset — textViewの端からのテキストマージン(UIEdgeInsets);textView.textContainer.lineFragmentPadding — 各行内の水平パディング;textView.textContainer.maximumNumberOfLines — 行制限(0 = 制限なし);textView.textContainer.exclusionPaths — テキストが回り込む領域(画像、カスタム形状)のUIBezierPath配列。ExclusionPathsにより複雑なレイアウトが可能になります:テキストが円形のプロフィール画像、アイコン、任意の形状の周りを回り込みます。動的なUITextViewの高さについては、KVOまたはデリゲートを介してcontentSizeを監視し、制約を更新します。
// 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]
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]を設定します。
iOSアプリケーションでのUITextViewの使用例を2つ見てみましょう。1つ目は、コンテンツ表示のための属性付きテキストとデータ検出器を備えた読み取り専用テキストビュー。2つ目は、コメントフォーム用の遅延プレースホルダーと動的な高さを備えた編集可能テキストビュー。どちらの例もUIKitのベストプラクティス(デリゲートプロトコル、Auto Layout、TextKit)を使用しています。
読み取り専用モードは、isEditable = falseとisSelectable = trueを設定することで有効になります。これにより、ユーザーはテキストを選択してリンクをタップできますが、編集はできません。リンクの自動検出のためにdataDetectorTypesを設定し、透明な背景のためにbackgroundColor = .clearを設定します。長いコンテンツの場合は、可読性のためにNSMutableParagraphStyle lineSpacing付きのattributedTextを使用します。テキスト内の主要なリンクにlink属性を追加します。
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のプレースホルダーは組み込まれていません — textViewの上にUILabelを配置するか、isEmptyチェック付きのattributedTextで実装します。シンプルなアプローチ:編集開始時に非表示になる灰色テキストのUILabel。textViewDidChangeでテキストの有無を確認し、プレースホルダーを表示/非表示にします。よりエレガントな解決策としては、入力テキストの色を設定するためにtypingAttributesプロパティを使用します。動的なtextViewの高さは、contentSizeの監視と制約の更新によって実現されます — これはチャットやコメントフォームの標準パターンです。
よくある質問
UITextViewには組み込みのプレースホルダーはありません。標準的な解決策:textViewの上に灰色テキストのUILabelを配置します。textViewDidBeginEditingでラベルを非表示にし、textViewDidEndEditingでテキストが空の場合は表示します。代替案:プレースホルダーとして灰色のattributedTextを使用し、編集開始時にリセットします。既成の解決策としては、KMPlaceholderTextViewライブラリまたはReactorKitを使用してください。
textContainerInset = .zeroおよびlineFragmentPadding = 0を設定します:textView.textContainerInset = UIEdgeInsets.zero;textView.textContainer.lineFragmentPadding = 0。さらに:textView.contentInset = .zero。これにより、textViewの端からテキストまでのマージンが完全に削除されます。lineFragmentPaddingのデフォルトは5であることに注意してください。
確認事項:isSelectable = true(インタラクションに必要)、dataDetectorTypesに.linkが含まれている、デリゲートがshouldInteractWithURLでfalseを返していない。textView.isEditable = trueの場合、リンクはシングルタップで利用不可になります — ダブルタップが必要です。編集可能なtextViewでインタラクティブなリンクを使用するには、textViewの上にUITapGestureRecognizerを追加し、URLを手動で処理します。
isScrollEnabled = trueを設定し、固定値で高さ制約を追加します。高さを超えるテキストはスクロールされます。最適なUXのためにはmaxHeightを使用します:contentSizeを監視し、高さ制約をmaxHeight以下に設定します。maxHeightを超えたらscrollEnabledを有効にします。これはメッセージ入力フィールドやコメントフォームの標準パターンです。
NSTextAttachmentを使用します:オブジェクトを作成し、画像とboundsを設定し、アタッチメントからNSAttributedStringを作成してtextView.attributedTextに挿入します。例:let attachment = NSTextAttachment();attachment.image = image;attachment.bounds = CGRect(x, y, width, height);let attributedString = NSAttributedString(attachment: attachment)。画像はテキストにインラインで表示され、テキストと一緒にスクロールします。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。