swiftui

How to add a toolbar above the keyboard


enter image description here

It's possible to create a Toolbar above keyboard in UIKit using the inputAccessoryView. But how can that be done for SwiftUI? Since, inputAccessoryView isn't supported for SwiftUI (Based on what I looked up online). I have limited knowledge on UIKit and Objective-C so not sure how I can combine SwiftUI and UIKit

import SwiftUI
import Combine

struct TipsView: View {
    @State private var amount = ""
    
    var body: some View {
        NavigationView {
            Form {
                Section (header: Text("Amount")) {
                    HStack (spacing: 1) {
                        if !amount.isEmpty {
                            Text("£")
                        }
                        TextField("Amount", text: $amount)
                            .keyboardType(.decimalPad)
                            .onReceive(Just(amount)) { newValue in
                                let filtered = newValue.filter { "0123456789.".contains($0)}
                                if filtered != newValue {
                                    amount = filtered
                                }
                            }
                    }//HStack
                }//Section
            }//Form
        }//NavigationView
    }
}

Solution

  • You can wrap a UITextField inside a UIViewRepresentable and then add a toolbar to the UITextField.

    For instance

    struct WrappedTextField: UIViewRepresentable {
        
        // binding...
        
        typealias UIViewType = UITextField
        
        func makeUIView(context: Context) -> UITextField {
            let textField = UITextField()
            textField.delegate = context.coordinator
            textField.addDoneButtonOnKeyboard()
            return textField
        }
        
        func updateUIView(_ uiView: UITextField, context: Context) {
            // update binding...
        }
        
        func makeCoordinator() -> Coordinator {
            return Coordinator()
        }
        
        public class Coordinator: NSObject, UITextFieldDelegate {
            // delegate methods...
        }
    }
    
    extension UITextField {
    
        func addDoneButtonOnKeyboard(){
            let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
            doneToolbar.barStyle = .default
            
            let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
            let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
            
            let items = [flexSpace, done]
            doneToolbar.items = items
            doneToolbar.sizeToFit()
            
            self.inputAccessoryView = doneToolbar
        }
        
        @objc func doneButtonAction(){
            self.resignFirstResponder()
        }
    }
    

    Then you'll be able to use it like a normal SwiftUI view

    var body: some View {
       WrappedTextField(...)
    }
    

    To see examples of how to create UIViewRepresentables checkout my repo here