如何在特定的 UIViewRepresentable TextField 以及常规 SwiftUI 文本字段上将 isUserInteractionEnabled 设置为 false

问题描述 投票:0回答:1

我有 SwiftUI View,其中有两个普通的 TextField 和一个 UIViewRepresentable UITextField。
我需要在键入值时关闭 UIViewRepresentable 上复制/粘贴/选择的可能性。
我通过在 CustomUITextField 结构(即 UIViewRepresentable UITextField)的协调器上调用的 textFieldShouldBeginEditing 函数下将 false 值设置为 isUserInteractionEnabled 来实现这一点。

问题是,如果我在某些 SwiftUI TextFields 上按回车键,则 textFieldShouldBeginEditing 会触发并将我的 CustomUITextField 设置为不可编辑,然后它才会处于活动状态,因此 CustomUITextField 变得不可触摸,因此我无法键入任何值。

这是 MRE

import SwiftUI

struct ContentView: View {
    @State private var name: String = ""
    @State private var phone: String = ""
    @State private var isFirstResponder = false
    
    var body: some View {
        VStack {
            Spacer()
            HStack {
                Text("A")
                TextField("", text: $name)
                    .border(Color.gray.opacity(0.3))
            }
            HStack {
                Text("B")
                CustomUITextField(isFirstResponder: $isFirstResponder, text: $phone)
                    .frame(height: 22)
                    .border(Color.gray.opacity(0.3))
            }
            Spacer()
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

struct CustomUITextField: UIViewRepresentable {
    @Binding var isFirstResponder: Bool
    @Binding var text: String
    
    init(isFirstResponder: Binding<Bool>, text: Binding<String>) {
        self._isFirstResponder = isFirstResponder
        self._text = text
    }
    
    func makeUIView(context: UIViewRepresentableContext<CustomUITextField>) -> UITextField {
        let textField = UITextField(frame: .zero)
        textField.text = text
        textField.delegate = context.coordinator
        
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUITextField>) {
        context.coordinator.listenToChanges = false
        if isFirstResponder != uiView.isFirstResponder {
            if isFirstResponder {
                uiView.becomeFirstResponder()
            } else {
                uiView.resignFirstResponder()
            }
        }
        uiView.text = text
        context.coordinator.listenToChanges = true
    }
    
    func makeCoordinator() -> Coordinator {
        let coordinator = Coordinator(isFirstResponder: $isFirstResponder, text: $text)
        return coordinator
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var isFirstResponder: Bool
        @Binding var text: String
        fileprivate var listenToChanges: Bool = false
        
        init(isFirstResponder: Binding<Bool>, text: Binding<String>) {
            self._isFirstResponder = isFirstResponder
            self._text = text
        }
        
        func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            textField.isUserInteractionEnabled = false
            return true
        }
        
        func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
            textField.isUserInteractionEnabled = true
            return true
        }
        
        func textFieldDidBeginEditing(_ textField: UITextField) {
            guard listenToChanges else { return }
            isFirstResponder = textField.isFirstResponder
        }
        
        func textFieldDidEndEditing(_ textField: UITextField) {
            guard listenToChanges else { return }
            isFirstResponder = textField.isFirstResponder
            text = textField.text ?? ""
        }
    }
}

如果您在文本字段 A 上输入某些值并按回车键,则无法激活文本字段 B。

当我点击 TextField A 在 textFieldShouldBeginEditing 中进行一些 if 语句时,我尝试通过绑定到 UIViewRepresentable 协调器来传递布尔值,但该函数在 A 字段上的 .onSubmit 事件之前触发。

对于解决这个问题有什么想法吗?

提前致谢

swiftui uitextfield uiviewrepresentable
1个回答
0
投票

不要像这样使用

textFieldShouldBeginEditing
,您应该做类似于这个答案的事情,即覆盖
canPerformAction
以返回 false。

struct CustomUITextField: UIViewRepresentable {
    @Binding var text: String
    
    class Wrapper: UITextField {
        override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
            false
        }
    }
    
    init(text: Binding<String>) {
        self._text = text
    }
    
    func makeUIView(context: UIViewRepresentableContext<CustomUITextField>) -> UITextField {
        let textField = Wrapper(frame: .zero)
        textField.textContentType = UITextContentType(rawValue: "")
        textField.text = text
        textField.delegate = context.coordinator
        
        return textField
    }
    
    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomUITextField>) {
        context.coordinator.textCallback = { text = $0 }
        uiView.text = text
    }
    
    func makeCoordinator() -> Coordinator {
        .init()
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        var textCallback: ((String) -> Void)?
        
        func textFieldDidEndEditing(_ textField: UITextField) {
            textCallback?(textField.text ?? "")
        }
    }
}

你永远不知道

textFieldShouldBeginEditing
何时被调用,因此在其中添加任何副作用通常是一个坏主意。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.