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

如何在Flutter中禁用TextField的iOS「Scan Text」功能?

禁用iOS 15及以上版本TextField上下文菜单中的「Scan Text」按钮

核心思路是拦截「Scan Text」对应的系统动作,通过重写canPerformAction(_:withSender:)方法阻止该菜单项显示。以下是SwiftUI和UIKit两种场景的实现方案:

SwiftUI 实现方案

由于SwiftUI原生TextField未直接提供禁用该菜单项的API,需通过UIViewRepresentable包装UITextField来实现:

import SwiftUI

struct NoScanTextField: UIViewRepresentable {
    @Binding var text: String
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.delegate = context.coordinator
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var text: String
        
        init(text: Binding<String>) {
            _text = text
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            text = textField.text ?? ""
        }
        
        // 拦截Scan Text动作
        override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
            if action == #selector(UIResponder.captureTextFromCamera(_:)) {
                return false
            }
            return super.canPerformAction(action, withSender: sender)
        }
    }
}

// 使用示例
struct ContentView: View {
    @State private var inputText = ""
    
    var body: some View {
        NoScanTextField(text: $inputText)
            .padding()
            .border(Color.gray)
    }
}

UIKit 实现方案

方式一:子类化UITextField

直接创建自定义TextField子类,重写动作拦截方法:

import UIKit

class NoScanTextField: UITextField {
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        // 禁用Scan Text
        if action == #selector(UIResponder.captureTextFromCamera(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }
}

// 使用示例
let textField = NoScanTextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40))
textField.borderStyle = .roundedRect
view.addSubview(textField)

方式二:通过ViewController的Delegate拦截

若不想子类化,可在TextField的代理所在类中重写动作拦截方法:

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        let textField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40))
        textField.borderStyle = .roundedRect
        textField.delegate = self
        view.addSubview(textField)
    }
    
    // 拦截Scan Text动作
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if action == #selector(UIResponder.captureTextFromCamera(_:)) {
            return false
        }
        return super.canPerformAction(action, withSender: sender)
    }
}

原理说明

「Scan Text」对应的系统内置动作是UIResponder的captureTextFromCamera(_:)方法,当系统准备生成上下文菜单时,会调用canPerformAction(_:withSender:)判断是否显示对应菜单项,返回false即可隐藏该选项。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:22:43