#swift #swiftui #uitextfield #uikeyboardtype
#swift #swiftui #uitextfield uitextfield #uikeyboardtype uikeyboardtype
Вопрос:
У меня есть структура jsondata, которая создается из файла JSON, который содержит это :
{
inputFieldTitle: "Total Cost",
keyboardType: "numberPad"
}
В моем коде, как я могу использовать атрибут keyboardType для инициализации перечисления UIKeyboardType, чтобы установить тип клавиатуры в моем текстовом поле?
Обычно мы делаем это, чтобы получить цифровую клавиатуру (SwiftUI). :
TextField(jsondata.inputFieldTitle) { ... }
.keyboardType(.numberPad)
Но в моем сценарии я не могу жестко задать keyboardType с помощью .NumberPad, я должен использовать то, что указано в jsondata, как я могу использовать это значение для установки keyboardType в текстовом поле? Это, очевидно, не работает, потому что UIKeyboardType имеет тип Int :
TextField(jsondata.inputFieldTitle) { ... }
.keyboardType(UIKeyboardType(rawValue: jsondata.keyboardType))
Есть какие-нибудь советы? Спасибо.
Комментарии:
1. Почему бы вам не создать функцию, которая преобразует вашу строку в требуемый Int для перечисления?
2. Это может быть решением, но мне было интересно, есть ли более простой способ?
3. Вы используете свою собственную конструкцию для типа клавиатуры, вам нужно преобразовать ее в требуемый тип, самый простой способ — создать функцию, которая выполняет преобразование, или вы могли бы сделать что-то вроде того, что предложил Аспери
Ответ №1:
Вы можете привести UIKeyboardType в соответствие с Decodable и реализовать свой собственный метод декодирования:
extension UIKeyboardType: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
let rawValue = try container.decode(Int.self)
guard let keyboardType = UIKeyboardType(rawValue: rawValue) else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "invalid UIKeyboardType rawValue: (rawValue)")
}
self = keyboardType
} catch DecodingError.typeMismatch {
let string = try container.decode(String.self)
guard let keyboardType = UIKeyboardType(string) else {
throw DecodingError.dataCorruptedError(in: container, debugDescription: "invalid UIKeyboardType string: (string)")
}
self = keyboardType
}
}
init?(_ string: String) {
switch string {
case "default": self = .default
case "asciiCapable": self = .asciiCapable
case "numbersAndPunctuation": self = .numbersAndPunctuation
case "URL": self = .URL
case "numberPad": self = .numberPad
case "phonePad": self = .phonePad
case "namePhonePad": self = .namePhonePad
case "emailAddress": self = .emailAddress
case "decimalPad": self = .decimalPad
case "twitter": self = .twitter
case "webSearch": self = .webSearch
case "asciiCapableNumberPad": self = .asciiCapableNumberPad
case "alphabet": self = .alphabet
default: return nil
}
}
}
extension UIKeyboardType: Encodable {
public func encode(to encoder: Encoder) throws {
var encoder = encoder.singleValueContainer()
let string: String
switch self {
case .default: string = "default"
case .asciiCapable: string = "asciiCapable"
case .numbersAndPunctuation: string = "numbersAndPunctuation"
case .URL: string = "URL"
case .numberPad: string = "numberPad"
case .phonePad: string = "phonePad"
case .namePhonePad: string = "namePhonePad"
case .emailAddress: string = "emailAddress"
case .decimalPad: string = "decimalPad"
case .twitter: string = "twitter"
case .webSearch: string = "webSearch"
case .asciiCapableNumberPad: string = "asciiCapableNumberPad"
}
try encoder.encode(string)
}
}
extension DataProtocol {
var string: String? { String(bytes: self, encoding: .utf8) }
}
Тестирование игровой площадки:
struct Test: Codable {
let inputFieldTitle: String
let keyboardType: UIKeyboardType
}
let numberPadJSON = """
{
"inputFieldTitle": "Total Cost",
"keyboardType": "numberPad"
}
"""
do {
let test = try JSONDecoder().decode(Test.self, from: Data(numberPadJSON.utf8))
print(test.keyboardType.rawValue) // 4
let encoded = try JSONEncoder().encode(test)
print(encoded.string ?? "") // {"inputFieldTitle":"Total Cost","keyboardType":"numberPad"}
} catch {
print(error)
}
Комментарии:
1. Это довольно аккуратно, так как моя структура jsondata поддается кодированию, поэтому это решение работает как по волшебству.
2. Я видел, что вы перешли с Кодируемого на Декодируемый. Почему вы решили внести это изменение и каков его эффект? Моя структура поддается кодированию, поэтому кодируемое решение было аккуратным.
3. Вы можете сохранить его кодируемым, если захотите. Если вам нужно его закодировать, просто убедитесь, что вы также внедрили часть кодирования, чтобы сохранить ее согласованной, иначе она будет кодироваться как Int.
Ответ №2:
UIKeyboardType
is-a Int
, поэтому вы не можете использовать rawValue
, потому что ваше значение json является строковым.
Вот возможное решение
extension UIKeyboardType {
static private let types = ["numberPad": numberPad] // << extend to all supported
init(_ value: String) {
if let result = Self.types[value] {
self = result
} else {
self = .default
}
}
}
и теперь вы можете использовать его как
TextField(jsondata.inputFieldTitle) { ... }
.keyboardType(UIKeyboardType(jsondata.keyboardType))
// .keyboardType(UIKeyboardType(jsondata.keyboardType ?? "")) // if optional
Комментарии:
1. Почему не просто
["numberPad": numberPad]
?types
уже является статическим свойствомUIKeyboardType
.Self.
является избыточным.