如何在UIScrollView中编程实现UITextView的文本高亮与滚动?
问题:禁用滚动的UITextView嵌套UIScrollView时,如何高亮文本并滚动到高亮区域?
我有一个禁用滚动的UITextView,嵌套在UIScrollView中,已通过以下代码实现指定文本的高亮:
@IBAction func click(_ sender: Any) { let attributedText = textView.attributedText! let attributedString: NSMutableAttributedString = NSMutableAttributedString(attributedString: attributedText) let range = NSRange(location: 0, length: attributedString.length) attributedString.removeAttribute(NSAttributedString.Key.backgroundColor, range: range) let searchedString = "Can you highlight and scroll?" do { let regex = try NSRegularExpression( pattern: NSRegularExpression.escapedPattern(for: searchedString), options: .caseInsensitive ) let targetedString = attributedString.string for match in regex.matches(in: targetedString, options: .withTransparentBounds, range: range) { print(">>>> found the 1st match") attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.yellow, range: match.range) break } } catch { print("\(error)") } textView.attributedText = attributedString }
高亮功能正常,但由于UITextView滚动已禁用,textView.scrollRangeToVisible(match.range)无法让高亮区域自动滚动到可视区域。请问该场景下,如何实现文本高亮并滚动到高亮区域?
解决方案
核心思路是通过UITextView计算高亮文本的位置,转换为外层UIScrollView的坐标后,让UIScrollView滚动到对应区域,具体实现步骤:
- 计算高亮文本在UITextView中的边界Frame
- 将该Frame从UITextView的坐标系统转换到外层UIScrollView的坐标系统
- 调用UIScrollView的
scrollRectToVisible(_:animated:)方法完成滚动
修改后的完整代码如下:
@IBAction func click(_ sender: Any) { guard let attributedText = textView.attributedText else { return } let attributedString = NSMutableAttributedString(attributedString: attributedText) let fullRange = NSRange(location: 0, length: attributedString.length) // 清除之前的高亮 attributedString.removeAttribute(.backgroundColor, range: fullRange) let searchedString = "Can you highlight and scroll?" do { let regex = try NSRegularExpression( pattern: NSRegularExpression.escapedPattern(for: searchedString), options: .caseInsensitive ) guard let match = regex.firstMatch(in: attributedString.string, options: .withTransparentBounds, range: fullRange) else { print("未找到匹配文本") return } // 添加高亮背景 attributedString.addAttribute(.backgroundColor, value: UIColor.yellow, range: match.range) textView.attributedText = attributedString // --- 滚动到高亮区域的核心代码 --- // 1. 获取高亮文本在UITextView中的Frame guard let startPos = textView.position(from: textView.beginningOfDocument, offset: match.range.location), let endPos = textView.position(from: startPos, offset: match.range.length), let textRange = textView.textRange(from: startPos, to: endPos) else { return } var highlightFrame = textView.firstRect(for: textRange) // 2. 转换为外层UIScrollView的坐标 highlightFrame = textView.convert(highlightFrame, to: scrollView) // 3. 让UIScrollView滚动到该区域(animated设为true开启平滑动画) scrollView.scrollRectToVisible(highlightFrame, animated: true) } catch { print("正则表达式错误:\(error)") } }
关键说明
textView.firstRect(for:)用于获取高亮文本在UITextView内部的边界坐标- 通过
convert(_:to:)完成坐标系转换,确保滚动位置对应外层UIScrollView的可视区域 - 如果需要让高亮区域居中显示,可以调整
highlightFrame的origin值后再调用滚动方法
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

