SwiftUI - добавление кнопки панели инструментов клавиатуры только для одного текстового поля добавляет ее для всех текстовых полей.
Задний план
У меня есть два s, один из которых имеет тип клавиатуры
Учитывая, что при использовании клавиатуры с десятичной панелью, чтобы закрыть ее, нет кнопки «Готово», скорее, как клавиша возврата стандартной клавиатуры, я хотел бы добавить кнопку «Готово» на панели инструментов над клавиатурой только для десятичной клавиатуры. в SwiftUI.
Проблема
Добавление a к любому по какой-либо причине добавляет его вместо этого ко всем s! Я пробовал условные модификаторы, используя сфокусированные состояния и проверяя наличие
Как я могу иметь только
Код
Обратите внимание, что я попытался создать минимальный пример, который вы можете просто скопировать и вставить в Xcode и запустить его самостоятельно. В Xcode 13.2 есть некоторые проблемы с отображением клавиатуры для
import SwiftUI
struct TestKeyboard: View {
@State var str: String = ""
@State var num: Float = 1.2
@FocusState private var focusedField: Field?
private enum Field: Int, CaseIterable {
case amount
case str
}
var body: some View {
VStack {
Spacer()
// I'm not adding .toolbar here...
TextField("A text field here", text: $str)
.focused($focusedField, equals: .str)
// I'm only adding .toolbar here, but it still shows for the one above..
TextField("", value: $num, formatter: FloatNumberFormatter())
.keyboardType(.decimalPad)
.focused($focusedField, equals: .amount)
.toolbar {
ToolbarItem(placement: .keyboard) {
Button("Done") {
focusedField = nil
}
}
}
Spacer()
}
}
}
// So you can preview it quickly
struct TestKeyboard_Previews: PreviewProvider {
static var previews: some View {
TestKeyboard()
}
}
7 ответов
Попробуйте сделать содержимое панели инструментов условным и переместите панель инструментов наружу, как показано ниже. (Сейчас нет возможности проверить - просто идея)
Примечание: проверьте на реальном устройстве
var body: some View {
VStack {
Spacer()
TextField("A text field here", text: $str)
.focused($focusedField, equals: .str)
TextField("", value: $num, formatter: FloatNumberFormatter())
.focused($focusedField, equals: .amount)
.keyboardType(.decimalPad)
Spacer()
}
.toolbar { // << here !!
ToolbarItem(placement: .keyboard) {
if field == .amount { // << here !!
Button("Done") {
focusedField = nil
}
}
}
}
}
Я много пробовал, но остановился на том, что ниже.
.focused($focusedField, equals: .zip)
.toolbar{
ToolbarItem(placement: .keyboard) {
switch focusedField{
case .zip:
HStack{
Spacer()
Button("Done"){
focusedField = nil
}
}
default:
Text("")
}
}
}
Это мое решение:
func textFieldSection(title: String,
text: Binding<String>,
keyboardType: UIKeyboardType,
focused: FocusState<Bool>.Binding,
required: Bool) -> some View {
TextField(
vm.placeholderText(isRequired: required),
text: text
)
.focused(focused)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
if focused.wrappedValue {
Spacer()
Button {
focused.wrappedValue = false
} label: {
Text("Done")
}
}
}
}
}
Для моего проекта у меня есть пятьTextField
представлений в одном представлении, поэтому я создал этот метод в расширении представления.
Я передаю уникальныйFocusState<Bool>.Binding
значение и используйте его в закрытии ToolbarItemGroup, чтобы определить, следует ли отображать содержимое (пробел, кнопка). Если конкретное TextFieldfocused
, мы отображаем содержимое панели инструментов (все остальные текстовые поля без фокуса не будут отображаться).
Решение для возврата цифровой клавиатуры в SwiftUI, кнопка панели инструментов над клавиатурой, сфокусированное поле
struct NumberOfBagsView:View{
@FocusState var isInputActive: Bool
@State var phoneNumber:String = ""
TextField("Place holder",
text: $phoneNumber,
onEditingChanged: { _ in
//do actions while writing something in text field like text limit
})
.keyboardType(.numberPad)
.focused($isInputActive)
.toolbar {
ToolbarItem(placement: .keyboard) {
Button("Done") {
print("done clicked")
isInputActive = false
}
}
}
}
Используя самоанализ , вы можете сделать что-то подобное в любой части вашего представления:
.introspectTextField { textField in
textField.inputAccessoryView = UIView.getKeyboardToolbar {
textField.resignFirstResponder()
}
}
и для
getKeyboardToolbar
:
extension UIView {
static func getKeyboardToolbar( _ callback: @escaping (()->()) ) -> UIToolbar {
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 44))
let doneButton = CustomBarButtonItem(title: "Done".localized, style: .done) { _ in
callback()
}
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolBar.items = [space, doneButton]
return toolBar
}
}
и для
CustomBarButtonItem
это элемент кнопки панели, который принимает закрытие
import UIKit
class CustomBarButtonItem: UIBarButtonItem {
typealias ActionHandler = (UIBarButtonItem) -> Void
private var actionHandler: ActionHandler?
convenience init(image: UIImage?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) {
self.init(image: image, style: style, target: nil, action: #selector(barButtonItemPressed(sender:)))
target = self
self.actionHandler = actionHandler
}
convenience init(title: String?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) {
self.init(title: title, style: style, target: nil, action: #selector(barButtonItemPressed(sender:)))
target = self
self.actionHandler = actionHandler
}
convenience init(barButtonSystemItem systemItem: UIBarButtonItem.SystemItem, actionHandler: ActionHandler?) {
self.init(barButtonSystemItem: systemItem, target: nil, action: #selector(barButtonItemPressed(sender:)))
target = self
self.actionHandler = actionHandler
}
@objc func barButtonItemPressed(sender: UIBarButtonItem) {
actionHandler?(sender)
}
}
Я нашел упаковку каждого
TextField
в своем собственном
NavigationView
дает каждому свой собственный контекст и, таким образом, уникальную панель инструментов. Это кажется неправильным, и я видел предупреждения об ограничениях в консоли. Используйте что-то вроде этого:
var body: some View {
VStack {
Spacer()
// I'm not adding .toolbar here...
NavigationView {
TextField("A text field here", text: $str)
.focused($focusedField, equals: .str)
}
// I'm only adding .toolbar here, but it still shows for the one above..
NavigationView {
TextField("", value: $num, formatter: FloatNumberFormatter())
.keyboardType(.decimalPad)
.focused($focusedField, equals: .amount)
.toolbar {
ToolbarItem(placement: .keyboard) {
Button("Done") {
focusedField = nil
}
}
}
}
Spacer()
}
}
Есть работа. Но другое TextField по-прежнему будет отображать панель инструментов.
struct TextFieldWithToolBar<Label, Toolbar>: View where Label: View, Toolbar: View {
@Binding public var text: String
public let toolbar: Toolbar?
@FocusState private var focus: Bool
var body: some View {
TextField(text: $text, label: { label })
.focused($focus)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
ZStack(alignment: .leading) {
if focus {
HStack {
toolbar
Spacer()
Button("Done") {
focus = false
}
}
.frame(width: UIScreen.main.bounds.size.width - 12)
}
}
}
}
}
}
TextFieldWithToolBar("Name", text: $name)
TextFieldWithToolBar("Name", text: $name){
Text("Only Brand")
}
TextField("Name", "Set The Name", text: $name)