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

iOS自定义SwiftUI键盘如何获取光标前的全部文本?

iOS自定义SwiftUI键盘如何获取光标前的全部文本?

嗨,我之前做自定义键盘的时候也踩过这个坑!确实textDocumentProxy.documentContextBeforeInput有个隐形的字符限制,大概200个左右,官方文档没明说,但实际跑起来就是这样。那些AI键盘能拿到全部文本,其实是用了个小trick——模拟光标移动来绕开这个限制,亲测有效!

核心思路

系统限制的只是单次调用documentContextBeforeInput返回的字符长度,但没禁止我们多次移动光标、多次获取文本再拼接。说白了就是:把光标一步步移到最左边,每次把新获取的文本拼到前面,最后再把光标挪回原来的位置,用户完全感知不到这个过程。

具体实现步骤(附Swift代码)

首先,我们可以给UIInputViewController写个扩展,封装这个获取逻辑——因为SwiftUI的自定义键盘本质上还是要靠UIInputViewController来获取textDocumentProxy:

extension UIInputViewController {
    func fetchFullTextBeforeCursor() -> String {
        var fullBeforeText = ""
        var totalMovedOffset = 0
        
        // 循环向左移动光标,直到无法再移动(到文本开头)
        while true {
            // 每次尝试向左移动200字符(刚好卡系统单次返回的上限)
            guard adjustTextPosition(byCharacterOffset: -200) else {
                // 已经到最左边了,把最后一段文本补上
                if let lastSegment = textDocumentProxy.documentContextBeforeInput {
                    fullBeforeText = lastSegment + fullBeforeText
                }
                break
            }
            
            // 把当前光标前的文本拼到结果的前面
            if let currentSegment = textDocumentProxy.documentContextBeforeInput {
                fullBeforeText = currentSegment + fullBeforeText
                totalMovedOffset += currentSegment.count
            }
        }
        
        // 把光标移回原来的位置,别让用户察觉我们动过光标
        adjustTextPosition(byCharacterOffset: totalMovedOffset)
        
        return fullBeforeText
    }
}

然后在SwiftUI的键盘视图里,我们需要用UIViewControllerRepresentable来包装UIInputViewController,才能调用这个方法:

// SwiftUI的键盘容器视图
struct CustomKeyboard: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIInputViewController {
        let inputVC = UIInputViewController()
        
        // 把你的SwiftUI键盘内容嵌入进来
        let keyboardContent = KeyboardContentView(
            fetchFullText: { inputVC.fetchFullTextBeforeCursor() }
        )
        let hostingVC = UIHostingController(rootView: keyboardContent)
        hostingVC.view.frame = inputVC.view.bounds
        inputVC.view.addSubview(hostingVC.view)
        
        return inputVC
    }
    
    func updateUIViewController(_ uiViewController: UIInputViewController, context: Context) {}
}

// 你的SwiftUI键盘内容视图示例
struct KeyboardContentView: View {
    let fetchFullText: () -> String
    
    var body: some View {
        VStack {
            Button("获取光标前全部文本") {
                let fullText = fetchFullText()
                print("拿到的完整前置文本:\(fullText)")
                // 这里可以处理拿到的文本,比如传给AI生成内容等
            }
            .padding()
            .background(Color.blue)
            .foregroundColor(.white)
            .cornerRadius(8)
            
            // 这里放你原来的键盘按键布局
        }
        .padding()
    }
}

注意事项

  • 一定要恢复光标位置:这是最关键的,如果忘了把光标移回去,用户会一脸懵,体验直接拉胯。
  • 特殊输入框兼容:像密码输入框这类安全控件,系统会禁止光标移动和文本获取,这种情况就别强求了,返回空或者提示用户即可。
  • 真机测试:模拟器有时候会有奇怪的光标移动bug,建议在真实设备上验证效果。

这个逻辑我自己在多个主流应用(备忘录、微信、Safari)里测过,和那些AI键盘的实现思路一致,完全能拿到光标前的全部文本。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 12:02:57