UITextView中如何根据用户选中内容获取对应完整区域的全部文本
问题场景

在iOS开发中,当用户在UITextView内选中部分文本时,需要获取系统显示的蓝色选择矩形框覆盖范围内的全部文本,而非仅获取用户手动拖拽选中的文本片段。
现有实现与存在的缺陷
当前常规的选中文本获取逻辑,仅能返回用户主动拖拽选中的文本内容,对应实现代码如下:
if let range = textView.selectedTextRange { let selectedText = textView.text(in: range) { //selectedText } }
该逻辑的局限性在于:仅依赖selectedTextRange的文本范围值,无法覆盖系统蓝色选中视觉框实际展示的全部文本(常见于选中范围跨行、文本边距偏移、换行导致视觉矩形覆盖文本范围与用户拖拽的逻辑选中范围不完全匹配的场景)。
具体技术实现方案
核心思路是直接读取系统用于绘制蓝色选中框的原生矩形数据源,而非依赖逻辑选中范围的映射值,具体实现步骤如下:
- 调用
UITextInput协议提供的selectionRects(for:)方法,传入当前的selectedTextRange,获取系统用来绘制蓝色选中框的所有连续矩形单元,每个单元对应确定的文本覆盖范围,完全匹配用户视觉看到的蓝色框边界 - 遍历所有返回的选中矩形单元,定位每个矩形上下、左右边界对应的文本位置,扩展聚合出完整的目标文本范围
- 合并重叠的范围区间后,通过
text(in:)方法读取对应范围内的全部文本
参考实现代码:
guard let selectedRange = textView.selectedTextRange else { return } // 获取系统绘制蓝色选中框的全部原生矩形数据 let selectionRects = textView.selectionRects(for: selectedRange) var targetStart = selectedRange.start var targetEnd = selectedRange.end for selectionRect in selectionRects { // 定位矩形左上角、右下角对应的文本位置 if let topPos = textView.closestPosition(to: selectionRect.rect.origin), textView.compare(topPos, to: targetStart) == .orderedAscending { targetStart = topPos } if let bottomPos = textView.closestPosition(to: CGPoint(x: selectionRect.rect.maxX, y: selectionRect.rect.maxY)), textView.compare(bottomPos, to: targetEnd) == .orderedDescending { targetEnd = bottomPos } } // 构造完整范围读取全量覆盖的文本 guard let fullCoveredRange = textView.textRange(from: targetStart, to: targetEnd) else { return } let fullCoveredText = textView.text(in: fullCoveredRange)
内容的提问来源于stack exchange,提问作者Hassan Taleb
相关产品推荐
相关产品推荐

