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

如何阻止外部HID扫描器向SwiftUI搜索栏TextField连续追加扫描值

问题原因

HID扫描器本质是模拟键盘输入,默认不会主动清空搜索框已有内容,而你的搜索框持续处于第一响应者状态,光标始终停留在文本末尾,新输入的条码字符会直接追加到原有内容之后,就会出现你遇到的重复拼接问题。

具体修改方案

1. 新增扫描输入判定逻辑

绝大多数HID扫描器出厂默认会在条码输入完成后自动发送回车符,同时扫描器输入字符的间隔远快于人工打字,我们可以通过这两个特征区分扫描输入和手动输入,实现新扫描内容直接替换旧内容。首先修改SearchBar的Coordinator代码:

class Coordinator: NSObject, UISearchBarDelegate {
    var onTextChanged: (String) -> Void
    @Binding var text: String
    // 新增属性:记录上次输入时间,区分扫描/手动输入
    private var lastInputTime: TimeInterval = 0
    private let scannerInputThreshold: TimeInterval = 0.05 // 扫描器单字符输入间隔通常小于50ms
    
    init(text: Binding<String>, onTextChanged: @escaping (String) -> Void) {
        _text = text
        self.onTextChanged = onTextChanged
    }
    
    // 新增文本变更前的拦截代理
    func searchBar(_ searchBar: UISearchBar, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let currentTime = Date().timeIntervalSince1970
        defer { lastInputTime = currentTime }
        
        // 判定1:收到回车符,说明单次扫描完成
        if text == "\n" {
            if let query = searchBar.text, !query.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                onTextChanged(query)
            }
            // 可选:如果不需要保留扫描结果在输入框,可直接清空,下次扫描直接输入新内容
            // searchBar.text = ""
            // self.text = ""
            return false
        }
        
        // 判定2:输入间隔小于阈值,判定为扫描器输入,直接替换全部原有内容
        if currentTime - lastInputTime < scannerInputThreshold && range.location == 0 {
            searchBar.text = text
            self.text = text
            return false
        }
        return true
    }
    
    // 原有textDidChange逻辑无需大幅调整
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        text = searchText
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(self.reload(_:)), object: searchBar)
        perform(#selector(self.reload(_:)), with: searchBar, afterDelay: 0.75)
    }
    
    @objc func reload(_ searchBar: UISearchBar) {
        guard let query = searchBar.text, query.trimmingCharacters(in: .whitespaces) != "" else {
            print("nothing to search")
            return
        }
        print(query)
    }
}

2. 优化第一响应者设置逻辑

你当前的代码每次刷新视图都会重复调用becomeFirstResponder,会导致光标始终固定在文本末尾,调整为仅初始化时设置一次即可:

func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
    uiView.text = text
    // 只在首次加载时设置第一响应者
    if context.coordinator.lastInputTime == 0 {
        uiView.becomeFirstResponder()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 18:48:02