🐕
SwiftUIでアルファベットと数字だけ入力できるTextField
SwiftUIアプリでIDを入力してもらう際にアルファベットと数字だけが入力できるTextField
が必要だったので自作しました。
コードはこちらです。
struct ContentView: View {
@State var username = ""
var body: some View {
TextField("[A-Za-z0-9]", text: $username)
.autocapitalization(.none)
.keyboardType(.asciiCapable)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
.onChange(of: username, perform: filter)
}
func filter(value: String) {
let validCodes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
let sets = CharacterSet(charactersIn: validCodes)
username = String(value.unicodeScalars.filter(sets.contains).map(Character.init))
}
}
onChange(of:perform:)
のof
で指定した引数が変化すると(上記の例ではusername)、perform
に指定したclosureが呼び出されます(filter)。
用意した文字セット(validCodes)からCharacterSet
を生成。引数のvalueに対してfilter
を実行して文字セットに含まれない文字を除外したのちmap
で再度String
に戻しています(少しまどろっこしい)。
余談
当初は以下のような実装でした。
func filter(value: String) {
let sets = CharacterSet.lowercaseLetters
.union(CharacterSet.uppercaseLetters)
.union(CharacterSet.decimalDigits)
username = String(value.unicodeScalars.filter(sets.contains).map(Character.init))
}
-
CharacterSet.lowercaseLetters
が小文字 -
CharacterSet.uppercaseLetters
が大文字 -
CharacterSet.decimalDigits
が数字
に該当します。当初はこれで良いと思ったのですがlowercaseLetters
やuppercaseLetters
にはラテン文字全般が含まれていてスルーされてしまいました(ダイアクリティカルマークが付いた文字、á
など)。
参考情報
onChange(of:perform:)
Adds a modifier for this view that fires an action when a specific value changes.
CharacterSet
A set of Unicode character values for use in search operations.
Discussion