Swift iOS实现带背景色包裹文本的自定义UITextView
自定义UITextView实现背景包裹文本、内边距、多行及圆角效果
核心实现思路
要实现背景色仅包裹文本而非整个控件,不能直接使用UITextView自带的backgroundColor,需通过自定义绘制实现。同时结合以下几点达成需求:
- 禁用滚动让视图自适应文本高度,支持多行显示;
- 重写文本区域方法添加内边距;
- 自定义绘制带圆角的背景,范围跟随文本内容动态调整。
Swift代码实现
自定义UITextView子类
import UIKit class CustomTextView: UITextView { // 可外部调整的文本内边距 var textInsets = UIEdgeInsets(top: 8, left: 12, bottom: 8, right: 12) { didSet { setNeedsDisplay() } } // 可外部调整的文本背景色 var textBackgroundColor: UIColor = .lightGray.withAlphaComponent(0.2) { didSet { setNeedsDisplay() } } // 可外部调整的圆角半径 var cornerRadius: CGFloat = 8 { didSet { setNeedsDisplay() } } override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) commonSetup() } required init?(coder: NSCoder) { super.init(coder: coder) commonSetup() } private func commonSetup() { // 禁用滚动,让视图自适应文本高度(支持多行) isScrollEnabled = false // 清空默认背景色,避免与自定义背景冲突 backgroundColor = .clear // 可选:设置默认字体 font = .systemFont(ofSize: 16) } // 重写文本显示区域,添加内边距 override func textRect(forBounds bounds: CGRect) -> CGRect { return bounds.inset(by: textInsets) } override func editingRect(forBounds bounds: CGRect) -> CGRect { return textRect(forBounds: bounds) } // 自定义绘制背景 override func draw(_ rect: CGRect) { guard let text = text, !text.isEmpty, let font = font else { super.draw(rect) return } // 获取文本的实际显示区域 let textDisplayRect = textRect(forBounds: rect) let textSize = text.boundingRect( with: CGSize(width: textDisplayRect.width, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil ).size // 计算背景矩形:文本区域向外扩展内边距 let backgroundRect = CGRect( x: textDisplayRect.origin.x, y: textDisplayRect.origin.y, width: textDisplayRect.width, height: textSize.height ).inset(by: UIEdgeInsets( top: -textInsets.top, left: -textInsets.left, bottom: -textInsets.bottom, right: -textInsets.right )) // 绘制圆角背景 let bgPath = UIBezierPath(roundedRect: backgroundRect, cornerRadius: cornerRadius) textBackgroundColor.setFill() bgPath.fill() // 绘制文本 super.draw(rect) } // 文本变化或布局更新时重绘背景 override func layoutSubviews() { super.layoutSubviews() setNeedsDisplay() } }
使用示例
// 在ViewController中初始化并配置 let customTextView = CustomTextView() customTextView.text = "这是一段支持多行显示的测试文本,背景色会精准包裹文本内容,同时带有自定义内边距和圆角样式。" customTextView.textBackgroundColor = .systemBlue.withAlphaComponent(0.1) customTextView.cornerRadius = 12 customTextView.textInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15) customTextView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(customTextView) // 添加约束(根据需求调整) NSLayoutConstraint.activate([ customTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), customTextView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), customTextView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20) ])
关键注意事项
- 禁用滚动:必须设置
isScrollEnabled = false,否则UITextView会固定高度,无法自适应文本内容实现多行效果。 - 背景绘制逻辑:通过计算文本实际占用尺寸,动态调整背景范围,确保背景仅包裹文本而非整个控件。
- 动态更新:当文本内容、内边距或圆角属性变化时,通过
setNeedsDisplay()触发重绘,保证UI同步更新。 - 编辑支持:重写
editingRect方法确保编辑状态下内边距和背景显示与正常状态一致。
内容的提问来源于stack exchange,提问作者nicover
相关产品推荐
相关产品推荐

