UITextView:是什么、多行输入及工作原理

作者: IT Sectr 发布日期: 2026-07-07 阅读时间: 8 分钟

UITextView是UIKit的多行文本组件,继承自UIScrollView,支持编辑带有嵌入链接和图像的属性文本。根据Apple Developer(2025)文档,UITextView提供UITextViewDelegate,包含textViewDidChange、shouldInteractWithURL和shouldInteractWithTextAttachment回调以处理交互。与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,支持占位符、left/right视图和清除按钮。UITextView是多行UIScrollView,拥有完整的TextKit系统用于属性文本。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。属性字符串允许在同一文本中设置不同字体、颜色、行间距、对齐方式和链接。属性:textView.attributedText = attributedString。NSAttributedString.Key的关键属性:font(.systemFont,.boldSystemFont,自定义UIFont),foregroundColor,backgroundColor,paragraphStyle(带lineSpacing、alignment、lineBreakMode的NSMutableParagraphStyle),link(交互式链接的URL),underlineStyle,strikethroughStyle,shadow,baselineOffset,kern(字符间距)。使用init(string:,attributes:)创建attributedString,或使用NSMutableAttributedString向不同范围添加属性。UITextView自动将链接(link attribute)显示为交互式——点击时将调用委托方法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,链接在双击前无法点击——编辑时交互链接请使用手势识别器。

通过SFSafariViewController处理链接

SFSafariViewController是在iOS应用中打开链接的标准方式。在shouldInteractWithURL方法中创建带有URL的SFSafariViewController,并通过模态或navigationController呈现。对于通用链接,使用UIApplication.shared.open(url, options)——但这会离开应用。要禁止打开链接,在shouldInteractWithURL中返回false并自行处理URL。

Text Container系统:边距和exclusionPaths

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
// 通过contentSize实现动态UITextView高度
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
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 attribute不冲突——两种机制并行工作。对于只读UITextView(新闻、文章),设置dataDetectorTypes = [.link, .phoneNumber]。

  • .link — URL、电子邮件地址;显示为蓝色链接
  • .phoneNumber — 电话号码;点击显示呼叫操作
  • .address — 邮政地址;点击打开地图
  • .calendarEvent — 日期和时间;点击创建日历事件
  • .flightNumber — 航班号(iOS 16+);快速航班检查

UITextView代码示例

让我们看看在iOS应用中使用UITextView的两个实际示例。第一个——带有属性文本和data detector的只读文本视图,用于显示内容。第二个——带有惰性占位符和动态高度的可编辑文本视图,用于评论表单。两个示例均使用UIKit最佳实践:委托协议、Auto Layout和TextKit。

带内容和链接的只读UITextView

只读模式通过设置isEditable = false和isSelectable = true启用。这允许用户选择文本和点击链接,但不能编辑。为自动检测链接设置dataDetectorTypes,为透明背景设置backgroundColor = .clear。显示长内容时,使用带有NSMutableParagraphStyle lineSpacing的attributedText以提高可读性。为文本中的关键链接添加link attributes。

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 }
        // 从URL加载内容并设置attributedText
    }
}

带占位符的可编辑UITextView

占位符对于UITextView并非内置——通过textView上方的UILabel或通过attributedText配合isEmpty检查实现。简单方法:带有灰色文本的UILabel,编辑开始时隐藏。在textViewDidChange中检查文本是否存在并隐藏/显示占位符。更优雅的解决方案,使用typingAttributes属性设置输入文本的颜色。文本视图的动态高度通过观察contentSize和更新约束实现——这是聊天和评论表单的标准模式。

常见问题

如何在UITextView中添加占位符?

UITextView没有内置占位符。标准解决方案:在textView上方添加带灰色文本的UILabel。在textViewDidBeginEditing中隐藏标签,在textViewDidEndEditing中如果文本为空则显示。替代方案:使用attributedText以灰色作为占位符,并在开始编辑时重置。现成解决方案请使用KMPlaceholderTextView或ReactorKit库。

如何移除UITextView中的边距?

设置textContainerInset = .zero和lineFragmentPadding = 0:textView.textContainerInset = UIEdgeInsets.zero; textView.textContainer.lineFragmentPadding = 0。另外:textView.contentInset = .zero。这将完全移除从textView边缘到文本的边距。请注意lineFragmentPadding默认值为5。

为什么UITextView不打开链接?

检查:isSelectable = true(交互必需),dataDetectorTypes包含.link,委托在shouldInteractWithURL中未返回false。如果textView.isEditable = true,链接无法通过单次点击——需要双击。在可编辑文本视图中使用交互链接时,请在textView上方添加UITapGestureRecognizer并手动处理URL。

如何创建固定高度带滚动的UITextView?

设置isScrollEnabled = true并添加固定值的height约束。超出高度的文本将可滚动。为获得最佳用户体验,使用maxHeight:观察contentSize并将height约束设置不超过maxHeight。超出maxHeight时启用scrollEnabled。这是消息和评论输入字段的标准模式。

如何在UITextView中插入图像?

使用NSTextAttachment:创建对象,设置image和bounds,然后从attachment创建NSAttributedString并插入到textView.attributedText。示例:let attachment = NSTextAttachment(); attachment.image = image; attachment.bounds = CGRect(x, y, width, height); let attributedString = NSAttributedString(attachment: attachment)。图像将内嵌显示在文本中并随文本一起滚动。

总结

  • UITextView — UIKit多行文本组件,继承UIScrollView,支持TextKit
  • NSAttributedString — 格式化字体、颜色、链接和段落的关键功能
  • UITextViewDelegate — 管理编辑并处理链接和附件的点击
  • Data Detector Types — 通过NSDataDetector自动检测URL、电话、地址和日期
  • Text Container — 包含exclusionPaths、lineFragmentPadding和textContainerInset的布局系统
  • 占位符 — 非内置,通过UILabel或带灰色的attributedText实现
  • 动态高度 — 观察contentSize并更新约束以实现自动高度
  • UITextView与UITextField的区别在于支持多行、属性、滚动和data detectors

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读