使用自定义按钮扩展 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
}
}
}
}
我正在尝试找到一种向 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
}
}
}
}