🐕
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