UITextView: nó là gì, nhập nhiều dòng và nguyên lý hoạt động

Tác giả: IT Sectr Đã đăng: 2026-07-07 Thời gian đọc: 8 phút

UITextView là thành phần văn bản nhiều dòng của UIKit, kế thừa từ UIScrollView và hỗ trợ chỉnh sửa văn bản có thuộc tính với liên kết và hình ảnh nhúng. Theo tài liệu Apple Developer (2025), UITextView cung cấp UITextViewDelegate với các callback textViewDidChange, shouldInteractWithURL và shouldInteractWithTextAttachment để xử lý tương tác. Không giống UITextField, UITextView hỗ trợ cuộn, kiểu văn bản qua typingAttributes và dataDetectorTypes để tự động phát hiện liên kết, địa chỉ và ngày tháng. Đây là thành phần chính để hiển thị nội dung và nhập văn bản nhiều dòng trong ứng dụng iOS.

Các điểm chính

  • UITextView — trường văn bản nhiều dòng trong UIKit, kế thừa UIScrollView với hỗ trợ chỉnh sửa
  • NSAttributedString — hỗ trợ văn bản có thuộc tính: phông chữ, màu sắc, khoảng cách dòng, liên kết
  • UITextViewDelegate — quản lý qua textViewDidChange, shouldInteractWithURL, didBeginEditing
  • Data Detector Types — tự động phát hiện liên kết, địa chỉ, ngày tháng, số điện thoại
  • Text Container — hệ thống textContainer, exclusionPaths và lineFragmentPadding cho bố cục tùy chỉnh

UITextView là gì

UITextView là một thành phần UIKit được thiết kế để hiển thị và chỉnh sửa văn bản nhiều dòng. Không giống UILabel, UITextView hỗ trợ chọn văn bản, chỉnh sửa, cuộn khi nội dung vượt quá kích thước và văn bản có thuộc tính. Là lớp con của UIScrollView, UITextView tự động bao gồm cuộn dọc và ngang khi nội dung tràn — điều này được cấu hình qua isScrollEnabled. Lớp hỗ trợ chỉnh sửa thông qua thuộc tính isEditable: đặt thành false cho chế độ chỉ đọc. UITextView hoạt động với NSLayoutManager thông qua hệ thống TextKit: NSTextStorage (lưu trữ văn bản có thuộc tính) → NSLayoutManager (bố cục dòng) → NSTextContainer (hình học vùng văn bản). Kiến trúc này cho phép bố cục tùy chỉnh với bao quanh hình ảnh, văn bản nhiều cột và bố cục văn bản phức tạp. UITextView được sử dụng để hiển thị bài viết, mô tả, nhật ký, bình luận và bất kỳ văn bản nhiều dòng nào trong iOS.

UITextView so với UITextField: Khác biệt chính

Sự khác biệt giữa UITextViewUITextField vượt xa số lượng dòng. UITextField là UIControl một dòng với hỗ trợ placeholder, chế độ xem trái/phải và nút xóa. UITextView là UIScrollView nhiều dòng với hệ thống TextKit đầy đủ cho văn bản có thuộc tính. UITextField không hỗ trợ NSAttributedString ở cấp độ hiển thị (chỉ qua attributedText với hạn chế), UITextView xử lý NSAttributedString hoàn toàn với các phông chữ, kiểu đoạn văn và hình ảnh nhúng khác nhau. UITextField có nút xóa tích hợp (clearButtonMode), UITextView thì không — cần triển khai tùy chỉnh. UITextField tự động thay đổi kích thước theo nội dung (intrinsicContentSize), UITextView yêu cầu quản lý chiều cao thủ công qua quan sát contentSize hoặc ràng buộc Auto Layout. UITextView hỗ trợ dataDetectorTypes (tự động phát hiện liên kết), UITextField hỗ trợ từ iOS 16+. Để nhập văn bản nhiều dòng (bình luận, ghi chú, tin nhắn) hãy chọn UITextView. Cho trường biểu mẫu (tên, email, mật khẩu) hãy sử dụng UITextField.

Tính năngUITextViewUITextField
DòngNhiều dòngMột dòng
PlaceholderKhông (tùy chỉnh)Tích hợp
Thuộc tính văn bảnNSAttributedString đầy đủGiới hạn
Data DetectorsHỗ trợ đầy đủiOS 16+
Hình ảnh inlineQua NSTextAttachmentKhông hỗ trợ
CuộnTích hợp (UIScrollView)Không
Chế độ xem Trái/PhảiKhôngTích hợp

NSAttributedString và Định dạng Văn bản

NSAttributedString là khả năng cơ bản của UITextView giúp phân biệt nó với UITextField và UILabel. Một chuỗi có thuộc tính cho phép đặt các phông chữ, màu sắc, khoảng cách dòng, căn chỉnh và liên kết khác nhau trong cùng một văn bản. Thuộc tính: textView.attributedText = attributedString. Các thuộc tính chính của NSAttributedString.Key: font (.systemFont, .boldSystemFont, UIFont tùy chỉnh), foregroundColor, backgroundColor, paragraphStyle (NSMutableParagraphStyle với lineSpacing, alignment, lineBreakMode), link (URL cho liên kết tương tác), underlineStyle, strikethroughStyle, shadow, baselineOffset, kern (khoảng cách chữ). Để tạo attributedString sử dụng init(string:, attributes:) hoặc NSMutableAttributedString để thêm thuộc tính vào các phạm vi khác nhau. UITextView tự động hiển thị liên kết (thuộc tính link) dưới dạng tương tác — nhấn vào sẽ kích hoạt phương thức ủy quyền shouldInteractWithURL. Để đặt lại thuộc tính cho đầu vào mới, sử dụng 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 và Xử lý Liên kết

UITextViewDelegate là một giao thức quản lý việc chỉnh sửa và tương tác với văn bản. Các phương thức chính: textViewDidBeginEditing(textView) — được gọi khi bắt đầu chỉnh sửa; textViewDidEndEditing — khi kết thúc chỉnh sửa; textViewDidChange — mỗi khi văn bản thay đổi; textViewDidChangeSelection — khi vùng chọn thay đổi; textViewShouldInteractWithURL — khi nhấn vào liên kết (trả về Bool, cho phép chuyển hướng); textViewShouldInteractWithTextAttachment — khi nhấn vào hình ảnh nhúng. Để xử lý liên kết bên trong UITextView, ghi đè shouldInteractWithURL — trong đó bạn có thể: mở URL trong SFSafariViewController, hiển thị UIAlertController để xác nhận, xử lý lược đồ URL tùy chỉnh. Quan trọng: nếu textView.isEditable = true, các liên kết không khả dụng cho một lần chạm — cần chạm hai lần. Để có liên kết tương tác trong textView có thể chỉnh sửa, hãy sử dụng gesture recognizers.

Xử lý Liên kết qua SFSafariViewController

SFSafariViewController là cách tiêu chuẩn để mở liên kết trong ứng dụng iOS. Trong phương thức shouldInteractWithURL, tạo SFSafariViewController với URL và trình bày nó theo kiểu modal hoặc qua navigationController. Đối với liên kết phổ quát, sử dụng UIApplication.shared.open(url, options) — nhưng điều này thoát khỏi ứng dụng. Để ngăn mở liên kết, trả về false trong shouldInteractWithURL và tự xử lý URL.

Hệ thống Text Container: Lề và Exclusion Paths

NSTextContainer là một phần của kiến trúc TextKit, xác định vùng hình học nơi văn bản UITextView được hiển thị. Mỗi UITextView có một textContainer tiêu chuẩn, có thể cấu hình qua: textView.textContainerInset — lề văn bản từ các cạnh textView (UIEdgeInsets); textView.textContainer.lineFragmentPadding — đệm ngang bên trong mỗi dòng; textView.textContainer.maximumNumberOfLines — giới hạn dòng (0 = không giới hạn); textView.textContainer.exclusionPaths — mảng UIBezierPath cho các vùng mà văn bản cần bao quanh (hình ảnh, hình dạng tùy chỉnh). ExclusionPaths cho phép bố cục phức tạp: văn bản bao quanh ảnh hồ sơ hình tròn, biểu tượng hoặc bất kỳ hình dạng tùy ý nào. Để có chiều cao UITextView động, hãy quan sát contentSize qua KVO hoặc ủy quyền và cập nhật các ràng buộc.

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: Tự động Phát hiện

dataDetectorTypes là thuộc tính UITextView tự động nhận dạng và làm cho một số loại dữ liệu trong văn bản trở nên tương tác: .link (URL, email), .phoneNumber (số điện thoại), .address (địa chỉ), .calendarEvent (ngày và sự kiện), .flightNumber (số chuyến bay), .lookupSuggestion (gợi ý tìm kiếm), .trackingNumber (số theo dõi), .money (số tiền), .shipmentTrackingNumber, .all (tất cả loại). Data Detector hoạt động với NSDataDetector và URL, tự động làm nổi bật dữ liệu được phát hiện. Để tùy chỉnh xử lý, hãy đặt dataDetectorTypes và ghi đè shouldInteractWithURL trong ủy quyền. Quan trọng: dataDetectorTypes chỉ hoạt động cho URL và phoneNumber mà không cần thiết lập thêm — các loại khác có thể yêu cầu iOS 16+. Data Detector không xung đột với thuộc tính link trong NSAttributedString — cả hai cơ chế hoạt động song song. Đối với UITextView chỉ đọc có nội dung (tin tức, bài viết), hãy đặt dataDetectorTypes = [.link, .phoneNumber].

  • .link — URL, địa chỉ email; hiển thị dưới dạng liên kết màu xanh
  • .phoneNumber — số điện thoại; chạm vào hiển thị hành động Gọi
  • .address — địa chỉ bưu chính; chạm vào mở Maps
  • .calendarEvent — ngày và giờ; chạm vào tạo sự kiện lịch
  • .flightNumber — số chuyến bay (iOS 16+); kiểm tra chuyến bay nhanh

Ví dụ Mã với UITextView

Hãy xem xét hai ví dụ thực tế về việc sử dụng UITextView trong ứng dụng iOS. Ví dụ đầu tiên — chế độ xem văn bản chỉ đọc với văn bản có thuộc tính và trình phát hiện dữ liệu để hiển thị nội dung. Ví dụ thứ hai — chế độ xem văn bản có thể chỉnh sửa với trình giữ chỗ lười biếng và chiều cao động cho biểu mẫu bình luận. Cả hai ví dụ đều sử dụng các phương pháp hay nhất của UIKit: giao thức ủy quyền, Auto Layout và TextKit.

UITextView Chỉ đọc với Nội dung và Liên kết

Chế độ chỉ đọc được kích hoạt bằng cách đặt isEditable = false và isSelectable = true. Điều này cho phép người dùng chọn văn bản và nhấn vào liên kết, nhưng không chỉnh sửa. Đặt dataDetectorTypes để tự động phát hiện liên kết, backgroundColor = .clear cho nền trong suốt. Đối với nội dung dài, sử dụng attributedText với NSMutableParagraphStyle lineSpacing để dễ đọc. Thêm thuộc tính link cho các liên kết chính trong văn bản.

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 Có thể Chỉnh sửa với Trình giữ chỗ

Trình giữ chỗ cho UITextView không được tích hợp sẵn — hãy triển khai nó qua UILabel phía trên textView hoặc qua attributedText với kiểm tra isEmpty. Một cách tiếp cận đơn giản: UILabel với văn bản màu xám ẩn đi khi bắt đầu chỉnh sửa. Trong textViewDidChange, kiểm tra sự hiện diện của văn bản và ẩn/hiện trình giữ chỗ. Để có giải pháp thanh lịch hơn, hãy sử dụng thuộc tính typingAttributes để đặt màu văn bản đầu vào. Chiều cao động của textView đạt được bằng cách quan sát contentSize và cập nhật các ràng buộc — đây là mẫu tiêu chuẩn cho trò chuyện và biểu mẫu bình luận.

Câu hỏi Thường gặp

Làm thế nào để thêm trình giữ chỗ vào UITextView?

UITextView không có trình giữ chỗ tích hợp. Giải pháp tiêu chuẩn: thêm UILabel với văn bản màu xám phía trên textView. Trong textViewDidBeginEditing ẩn nhãn, trong textViewDidEndEditing hiển thị nếu văn bản trống. Thay thế: sử dụng attributedText với màu xám làm trình giữ chỗ và đặt lại khi bắt đầu chỉnh sửa. Để có giải pháp sẵn sàng, hãy sử dụng thư viện KMPlaceholderTextView hoặc ReactorKit.

Làm thế nào để xóa lề trong UITextView?

Đặt textContainerInset = .zero và lineFragmentPadding = 0: textView.textContainerInset = UIEdgeInsets.zero; textView.textContainer.lineFragmentPadding = 0. Thêm vào: textView.contentInset = .zero. Điều này sẽ loại bỏ hoàn toàn lề từ các cạnh textView đến văn bản. Lưu ý rằng lineFragmentPadding mặc định là 5.

Tại sao UITextView không mở liên kết?

Kiểm tra: isSelectable = true (cần thiết cho tương tác), dataDetectorTypes bao gồm .link, ủy quyền không trả về false trong shouldInteractWithURL. Nếu textView.isEditable = true, các liên kết không khả dụng cho một lần chạm — cần chạm hai lần. Để có liên kết tương tác trong textView có thể chỉnh sửa, thêm UITapGestureRecognizer phía trên textView và xử lý URL thủ công.

Làm thế nào để tạo UITextView chiều cao cố định với cuộn?

Đặt isScrollEnabled = true và thêm ràng buộc chiều cao với giá trị cố định. Văn bản vượt quá chiều cao sẽ cuộn. Để có UX tối ưu, sử dụng maxHeight: quan sát contentSize và đặt ràng buộc chiều cao không cao hơn maxHeight. Khi vượt quá maxHeight, bật scrollEnabled. Đây là mẫu tiêu chuẩn cho trường nhập tin nhắn và bình luận.

Làm thế nào để chèn hình ảnh vào UITextView?

Sử dụng NSTextAttachment: tạo một đối tượng, đặt hình ảnh và bounds, sau đó tạo NSAttributedString từ tệp đính kèm và chèn vào textView.attributedText. Ví dụ: let attachment = NSTextAttachment(); attachment.image = image; attachment.bounds = CGRect(x, y, width, height); let attributedString = NSAttributedString(attachment: attachment). Hình ảnh sẽ hiển thị nội dòng trong văn bản và cuộn cùng với nó.

Tóm tắt

  • UITextView — thành phần văn bản nhiều dòng trong UIKit, kế thừa UIScrollView với hỗ trợ TextKit
  • NSAttributedString — khả năng chính để định dạng phông chữ, màu sắc, liên kết và đoạn văn
  • UITextViewDelegate — quản lý chỉnh sửa và xử lý chạm vào liên kết và tệp đính kèm
  • Data Detector Types — tự động phát hiện URL, điện thoại, địa chỉ và ngày tháng qua NSDataDetector
  • Text Container — hệ thống với exclusionPaths, lineFragmentPadding và textContainerInset cho bố cục
  • Trình giữ chỗ — không tích hợp, triển khai qua UILabel hoặc attributedText với màu xám
  • Chiều cao động — quan sát contentSize và cập nhật ràng buộc cho chiều cao tự động
  • UITextView khác UITextField ở hỗ trợ nhiều dòng, thuộc tính, cuộn và trình phát hiện dữ liệu

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm