如何在UITextView中实现WhatsApp、Facebook式状态文本背景扩展样式
实现UITextView中文本区域动态背景(类似WhatsApp/Facebook/Instagram状态样式)
我懂你想要的效果——在UITextView里只给实际输入的文本部分加上背景色,而且输入时这个背景区域能跟着文本自动扩展,就像社交平台的状态输入框那样对吧?下面给你两种实用的实现方案,你可以根据需求选择:
方案一:利用NSAttributedString自带的背景属性(快速实现)
这是最简单直接的方式,通过给文本添加backgroundColor属性,UITextView会自动根据文本的布局渲染背景,输入文本时背景也会跟着自动适配扩展。
实现步骤
- 监听UITextView的文本变化事件
- 每次文本更新时,给全部文本添加背景色属性(保留原有文本的其他格式属性)
代码示例
class StatusTextView: UITextView { override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) setupBaseConfig() } required init?(coder: NSCoder) { super.init(coder: coder) setupBaseConfig() } private func setupBaseConfig() { delegate = self // 让TextView本身背景透明,只显示文本的背景色 backgroundColor = .clear // 初始设置文本背景 updateTextBackground() } private func updateTextBackground() { let mutableAttributedText = NSMutableAttributedString(attributedString: self.attributedText) // 这里用淡灰色作为文本背景,可根据需求替换颜色 mutableAttributedText.addAttribute( .backgroundColor, value: UIColor.systemGray5, range: NSRange(location: 0, length: mutableAttributedText.length) ) self.attributedText = mutableAttributedText } } extension StatusTextView: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { updateTextBackground() } }
方案二:自定义绘制背景(更灵活的样式控制)
如果需要更精细的样式调整(比如圆角、内边距、边框等),可以重写UITextView的绘制方法,手动绘制文本区域的背景。
实现步骤
- 获取文本的实际布局范围
- 根据文本占用的区域绘制自定义背景
- 监听文本变化,触发重绘
代码示例
class CustomStatusTextView: UITextView { // 可自定义的样式参数 private let textBgColor = UIColor.systemGray5 private let cornerRadius: CGFloat = 8.0 private let textInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) setupBaseConfig() } required init?(coder: NSCoder) { super.init(coder: coder) setupBaseConfig() } private func setupBaseConfig() { backgroundColor = .clear textContainerInset = textInsets // 监听文本变化通知 NotificationCenter.default.addObserver( self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: self ) } @objc private func textDidChange() { // 文本变化时触发重绘 setNeedsDisplay() } override func draw(_ rect: CGRect) { super.draw(rect) guard let layoutManager = layoutManager, let textContainer = textContainer else { return } // 获取文本实际占用的矩形范围 let fullTextRange = NSRange(location: 0, length: textStorage.length) let textRect = layoutManager.boundingRect(forGlyphRange: fullTextRange, in: textContainer) // 调整背景矩形,适配内边距和圆角 let backgroundRect = textRect.inset(by: UIEdgeInsets( top: -textInsets.top, left: -textInsets.left, bottom: -textInsets.bottom, right: -textInsets.right )).offsetBy(dx: textContainerInset.left, dy: textContainerInset.top) // 绘制带圆角的背景 let bgPath = UIBezierPath(roundedRect: backgroundRect, cornerRadius: cornerRadius) textBgColor.setFill() bgPath.fill() } deinit { NotificationCenter.default.removeObserver(self) } }
注意事项
- 两种方案都支持多行文本自动适配,背景会随着文本换行自动扩展
- 如果使用方案二,还可以额外添加边框、阴影等效果,进一步贴近社交平台的样式
- 记得将UITextView自身的
backgroundColor设为透明,避免和自定义背景冲突
内容的提问来源于stack exchange,提问作者iOS Trainee.
相关产品推荐
相关产品推荐

