UITextView는 UIScrollView를 상속하고 링크와 이미지를 포함한 속성 텍스트 편집을 지원하는 UIKit의 여러 줄 텍스트 컴포넌트입니다. 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과 구별하는 기본 기능입니다. 속성 문자열을 사용하면 하나의 텍스트 내에서 다른 글꼴, 색상, 줄 간격, 정렬 및 링크를 설정할 수 있습니다. 속성: 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에서 대화형 링크를 사용하려면 제스처 인식기를 사용합니다.
SFSafariViewController는 iOS 애플리케이션에서 링크를 여는 표준 방법입니다. shouldInteractWithURL 메서드에서 URL로 SFSafariViewController를 만들고 모달 또는 navigationController를 통해 표시합니다. 범용 링크의 경우 UIApplication.shared.open(url, options)를 사용합니다 — 그러나 애플리케이션 외부로 나갑니다. 링크 열기를 방지하려면 shouldInteractWithURL에서 false를 반환하고 URL을 직접 처리합니다.
NSTextContainer는 UITextView 텍스트가 표시되는 지오메트리 영역을 정의하는 TextKit 아키텍처의 일부입니다. 각 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를 사용하는 두 가지 실제 예제를 살펴보겠습니다. 첫 번째 — 콘텐츠 표시를 위한 속성 텍스트 및 데이터 감지기가 있는 읽기 전용 텍스트 뷰. 두 번째 — 댓글 양식을 위한 지연 플레이스홀더 및 동적 높이가 있는 편집 가능한 텍스트 뷰. 두 예제 모두 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 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.