You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift iOS实现带背景色包裹文本的自定义UITextView

自定义UITextView实现背景包裹文本、内边距、多行及圆角效果

核心实现思路

要实现背景色仅包裹文本而非整个控件,不能直接使用UITextView自带的backgroundColor,需通过自定义绘制实现。同时结合以下几点达成需求:

  1. 禁用滚动让视图自适应文本高度,支持多行显示;
  2. 重写文本区域方法添加内边距;
  3. 自定义绘制带圆角的背景,范围跟随文本内容动态调整。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 10:35:20