UITextView子类自定义NSAttributedString属性与自动补全问题
解决UITextView自动补全丢失自定义属性的问题
一、重写核心替换方法
系统处理键盘自动补全替换时,实际会调用replaceCharacters(in:with:)——这是UITextView继承自UITextInput协议的核心方法,你之前可能漏掉了它的重写。
直接重写这个方法,在替换时保留自定义属性:
override func replaceCharacters(in range: NSRange, with text: String) { // 获取替换位置的原有属性(包含你的.custom自定义属性) guard let targetAttributes = attributedText?.attributes(at: range.location, effectiveRange: nil) else { super.replaceCharacters(in: range, with: text) return } // 用原有属性创建带自定义标记的新文本 let newAttributedText = NSAttributedString(string: text, attributes: targetAttributes) // 调用父类方法完成替换,确保属性不丢失 super.replaceCharacters(in: range, with: newAttributedText) }
二、兜底修复方案
如果遇到某些系统版本的补全逻辑差异,还可以通过监听文本变化通知,事后修复丢失的自定义属性:
// 子类初始化时添加监听 override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) setupAttributeFixObserver() } required init?(coder: NSCoder) { super.init(coder: coder) setupAttributeFixObserver() } private func setupAttributeFixObserver() { NotificationCenter.default.addObserver( self, selector: #selector(recoverCustomAttributes), name: UITextView.textDidChangeNotification, object: self ) } @objc private func recoverCustomAttributes() { guard let fullText = attributedText else { return } let mutableText = NSMutableAttributedString(attributedString: fullText) // 这里假设自定义属性是全局统一的,取第一个字符的属性作为基准补全 guard let baseAttrs = fullText.attributes(at: 0, effectiveRange: nil) else { return } mutableText.addAttributes(baseAttrs, range: NSRange(location: 0, length: fullText.length)) attributedText = mutableText }
三、关键说明
- 之前
insertText只收到换行符,是因为系统自动补全的逻辑是先替换选中文本,再处理后续的换行插入,真正的替换逻辑在replaceCharacters(in:with:)里。 - 这个重写方法会覆盖所有文本替换场景(包括输入、粘贴、自动补全),不需要单独区分补全场景,统一处理即可保证属性不丢失。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

