使用自定义按钮扩展 SwiftUI 键盘

Extend SwiftUI Keyboard with Custom Button

我正在尝试找到一种向 SwiftUI 数字键盘添加键或按钮的方法。唯一的 我发现的参考资料说这是不可能的。在 Swift 世界我添加了一个工具栏 带有关闭键盘或执行其他功能的按钮。

我什至会构建一个带有顶部按钮的 ZStack 视图,但我找不到添加 numberPad 到我自己的看法。

在这种情况下,我真正想做的就是在数据为 进入。我首先尝试修改 SceneDelegate 以在点击时关闭,但是 只有当我点击另一个文本或文本字段视图时才有效 space 在视图上。

window.rootViewController = UIHostingController(rootView: contentView.onTapGesture {
    window.endEditing(true)
})

理想情况下,我会在左下方添加一个完成键 space。其次最好添加一个工具栏,如果 可以在 SwiftUI.

中完成

如有任何指导,我们将不胜感激。

Xcode 版本 11.2.1 (11B500)

使用 UIRepresentable 协议解决了问题

struct TestTextfield: UIViewRepresentable {
    @Binding var text: String
    var keyType: UIKeyboardType
    func makeUIView(context: Context) -> UITextField {
        let textfield = UITextField()
      textfield.keyboardType = keyType
        let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textfield.frame.size.width, height: 44))
        let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textfield.doneButtonTapped(button:)))
        toolBar.items = [doneButton]
        toolBar.setItems([doneButton], animated: true)
        textfield.inputAccessoryView = toolBar
        return textfield
    }
    
    func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
        
    }
}

extension  UITextField{
    @objc func doneButtonTapped(button:UIBarButtonItem) -> Void {
       self.resignFirstResponder()
    }

}

在内容视图中使用

struct ContentView : View {
    @State var text = ""
    
    var body: some View {
        TestTextfield(text: $text, keyType: UIKeyboardType.phonePad)
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50)
            .overlay(
                RoundedRectangle(cornerRadius: 16)
                    .stroke(Color.blue, lineWidth: 4)
        )
    }
}

如果 @Binding 存在问题,请实施符合 UITextFieldDelegate 的协调器 class。如果需要,这将使人们能够进一步自定义 TextField。

struct DecimalTextField: UIViewRepresentable {
     private var placeholder: String
     @Binding var text: String

     init(_ placeholder: String, text: Binding<String>) {
        self.placeholder = placeholder
        self._text = text
     } 

     func makeUIView(context: Context) -> UITextField {
        let textfield = UITextField()
        textfield.keyboardType = .decimalPad
        textfield.delegate = context.coordinator
        textfield.placeholder = placeholder
        let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textfield.frame.size.width, height: 44))
        let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textfield.doneButtonTapped(button:)))
        toolBar.items = [doneButton]
        toolBar.setItems([doneButton], animated: true)
        textfield.inputAccessoryView = toolBar
        return textfield
     }

     func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.text = text
     }

     func makeCoordinator() -> Coordinator {
        Coordinator(self)
     }

     class Coordinator: NSObject, UITextFieldDelegate {
        var parent: DecimalTextField
    
     init(_ textField: DecimalTextField) {
        self.parent = textField
     }
    
     func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
         if let currentValue = textField.text as NSString? {
             let proposedValue = currentValue.replacingCharacters(in: range, with: string) as String
             self.parent.text = proposedValue
         }
         return true
     }
   }
 }

我使用 SwiftUI-Introspect 库在 5 行中完成了!我遇到了一个问题,即可表示文本字段对填充和框架没有任何反应。一切都是用这个库决定的!

Link: https://github.com/siteline/SwiftUI-Introspect

import SwiftUI
import Introspect

struct ContentView : View {
@State var text = ""

var body: some View {
    TextField("placeHolder", text: $text)
       .keyboardType(.default)
       .introspectTextField { (textField) in
           let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: textField.frame.size.width, height: 44))
           let flexButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
           let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(textField.doneButtonTapped(button:)))
           doneButton.tintColor = .systemPink
           toolBar.items = [flexButton, doneButton]
           toolBar.setItems([flexButton, doneButton], animated: true)
           textField.inputAccessoryView = toolBar
        }
}

extension  UITextField {
   @objc func doneButtonTapped(button:UIBarButtonItem) -> Void {
      self.resignFirstResponder()
   }
}

output

iOS15

从 iOS15 开始,我们可以使用新的 keyboard ToolbarItemPlacement:

在键盘上方添加自定义视图
Form {
    ...
}
.toolbar {
    ToolbarItem(placement: .keyboard) {
        Button("Do something") {
            print("something")
        }
    }
}

您还可以将其与新的 @FocusState 属性 包装器结合使用,以从当前编辑的元素中移除焦点:

@FocusState private var isFocused: Bool
...

var body: some View {
    Form {
        TextField(...)
            .focused($isFocused)
    }
    .toolbar {
        ToolbarItem(placement: .keyboard) {
            Button("Done") {
                isFocused = false
            }
        }
    }
}