import UIKit import SwiftUI import Combine struct DoneTextField: View, UIViewRepresentable { var placeholder: String @Binding var text: String func makeUIView(context: Context) -> DoneUITextField { let field = DoneUITextField() field.placeholder = placeholder field.keyboardType = .numberPad field.textBinding = $text field.configure() return field } func updateUIView(_ uiView: DoneUITextField, context: Context) { } static func dismantleUIView(_ uiView: DoneUITextField, coordinator: ()) { uiView.subscription?.cancel() } } class DoneUITextField: UITextField, UITextFieldDelegate, ObservableObject { var toolbar: UIToolbar? var textBinding: Binding<String>? { didSet { text = textBinding?.wrappedValue } } var subscription: AnyCancellable? func configure() { if toolbar == nil { toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 44.0)) let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDone)) toolbar?.items = [doneButton] self.inputAccessoryView = toolbar } self.delegate = self subscription = NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: self) .sink { _ in if (self.text?.count ?? 0) >= 10 { self.text = String(self.text?.prefix(10) ?? "") } self.textBinding?.wrappedValue = self.text ?? "" } } @objc func handleDone() { self.resignFirstResponder() } }