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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:57:11