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

SwiftUI如何滚动文本至首个子字符串匹配位置?

问题

在iOS 15的SwiftUI应用中,我有一个用于显示长字符串的垂直滚动页面,代码如下:

struct TextScrollView: View {
    var formattedText: AttributedString
    var searchTerm: String?

    var body: some View {
        ScrollView {
            Text(self.formattedText)
        }
        .padding(.all)
        .font(.body)
    } //body
} //TextScrollView

需求是:如果传入searchTerm,且该字符串在formattedText中至少存在一次匹配,则自动将文本滚动至首个匹配位置,逻辑示例如下:

if
    let searchTerm = self.searchTerm,
    let range = self.formattedText.range(of: searchTerm, options: .caseInsensitive)
{
    //scroll text to range
}

请问该需求是否可以实现?

可以实现,具体方案如下

iOS 15的SwiftUI原生Text和ScrollView没有直接提供获取文本范围位置并滚动的API,不过可以通过包装UIKit的UITextView来实现这个功能,步骤如下:

1. 实现UIViewRepresentable包装UITextView

创建一个支持自动滚动到指定文本范围的WrappedTextView:

struct WrappedTextView: UIViewRepresentable {
    let attributedText: NSAttributedString
    let searchTerm: String?
    let font: UIFont
    
    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.isEditable = false
        textView.isScrollEnabled = true
        textView.font = font
        textView.textContainerInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.attributedText = attributedText
        
        guard let searchTerm = searchTerm, !searchTerm.isEmpty else { return }
        
        // 查找匹配的文本范围
        let range = attributedText.mutableString.range(of: searchTerm, options: .caseInsensitive)
        if range.location != NSNotFound {
            // 滚动到匹配位置,带动画更自然
            uiView.scrollRangeToVisible(range)
        }
    }
}

2. 修改原TextScrollView使用包装后的组件

把原来的ScrollView和Text替换成上面的WrappedTextView,注意将AttributedString转换为NSAttributedString:

struct TextScrollView: View {
    var formattedText: AttributedString
    var searchTerm: String?

    var body: some View {
        WrappedTextView(
            attributedText: NSAttributedString(formattedText),
            searchTerm: searchTerm,
            font: UIFont.preferredFont(forTextStyle: .body)
        )
        .edgesIgnoringSafeArea(.bottom)
    }
}

补充说明

  • SwiftUI原生Text无法直接获取文本布局的位置信息,而UIKit的UITextView可以通过scrollRangeToVisible(_:)轻松实现滚动到指定文本范围的功能
  • 代码中保留了需求里的大小写不敏感匹配逻辑
  • 如果需要高亮搜索到的文本,可以在updateUIView方法中对attributedText进行富文本修改,比如添加背景色标记匹配内容

内容的提问来源于stack exchange,提问作者protasm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:37:34