SwiftUI 如何自定义 TextField、SecureField 和 TextEditor 的提交按钮?

41 min read

在 SwiftUI 中,可以通过 onCommit 属性来为 TextField、SecureField 和 TextEditor 添加自定义提交按钮。

但是,由于这些控件是原生控件,因此不支持直接更改提交按钮的样式。不过,可以通过一些技巧来实现一些定制化的效果。

以下是一些实现的方式:

  1. 使用自定义视图代替原生提交按钮,当点击自定义视图时执行提交的操作。例如,可以使用 Button 或者 Image 来代替提交按钮,然后在其点击事件中调用提交的动作。
struct CustomTextField: View {
    @State private var text: String = ""
    
    var body: some View {
        HStack {
            TextField("Input", text: $text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(Color.white)
            Button(action: {
                // Call submit action here
                print("Submit")
            }) {
                Image(systemName: "chevron.right.circle.fill")
                    .resizable()
                    .frame(width: 30, height: 30)
            }
        }
    }
}
  1. 使用 UIViewRepresentable 将原生的 UITextField 和 UITextView 包装为 SwiftUI 控件,并在包装的类中通过 UIResponderDelegate 接口实现提交事件的响应。
struct CustomTextField: UIViewRepresentable {
    @Binding var text: String
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
    }
    
    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = "Input"
        textField.borderStyle = .roundedRect
        textField.font = UIFont.systemFont(ofSize: 16)
        textField.autocapitalizationType = .none 
        textField.keyboardType = .default
        textField.returnKeyType = .done
        return textField
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: CustomTextField
        
        init(_ textField: CustomTextField) {
            self.parent = textField
        }
        
        func textFieldDidChangeSelection(_ textField: UITextField) {
            parent.text = textField.text ?? ""
        }
        
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            textField.resignFirstResponder()
            // Call submit action here
            print("Submit")
            return true
        }
    }
}

struct ContentView: View {
    @State private var text: String = ""
    
    var body: some View {
        VStack {
            CustomTextField(text: $text)
        }
    }
}

请注意,以上官方文档中提供的解决方案和一些开源库都可能会导致应用程序无法通过 App Store 审核。一些解决方案可以从途径得到积极反馈,最终修改可能是相同或不同的,这取决于 Apple 的判断。