私はswiftUIとiOを初めて使用し、数字のみを受け入れる入力フィールドを作成しようとしています
TextField("Total number of people", text: $numOfPeople)
TextFieldではアルファベット文字も使用できますが、ユーザーが数字のみを入力するように制限するにはどうすればよいですか?
私はswiftUIとiOを初めて使用し、数字のみを受け入れる入力フィールドを作成しようとしています
TextField("Total number of people", text: $numOfPeople)
TextFieldではアルファベット文字も使用できますが、ユーザーが数字のみを入力するように制限するにはどうすればよいですか?
回答:
キーボードのタイプを設定して、TextField
ユーザーが入力できるものを制限することができます。
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
Appleのドキュメントを見つけることができ、ここで、あなたはすべてのサポートされているキーボードの種類のリストを参照することができ、ここを。
注:iPadにはテンキーがないため、これはiPadでは機能しません。より良いソリューションのチェックアウトについては、以下のJohn Mのソリューションをご覧くださいhttps://stackoverflow.com/a/58736068/5508175
テンキーを表示することは良い最初のステップですが、実際には不正なデータの入力を防ぐことはできません。
あなたが本当にやりたいことは、次のように入力を無害化することです:
import SwiftUI
import Combine
struct StackOverflowTests: View {
@State private var numOfPeople = "0"
var body: some View {
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
.onReceive(Just(numOfPeople)) { newValue in
let filtered = newValue.filter { "0123456789".contains($0) }
if filtered != newValue {
self.numOfPeople = filtered
}
}
}
}
numOfPeople
変更されるたびに、非数値がフィルターで除外され、フィルターされた値が比較numOfPeople
されて、もう一度更新する必要があるかどうかが確認され、無効な入力がフィルターされた入力で上書きされます。
Just
パブリッシャーはあなたにそれを要求することに注意してくださいimport Combine
。
編集:
Just
パブリッシャーを説明するために、の値を変更したときに発生する次の概念的な概要を検討してくださいTextField
。
TextField
はa Binding
をとるためString
、フィールドの内容が変更されると、その変更が@State
変数に書き戻されます。@State
変更のマークが付けられると、SwiftUI body
はビューのプロパティを再計算します。body
計算中に、Just
発行者が作成されます。Combineには、時間の経過とともに値を出力するさまざまなパブリッシャーがたくさんありますが、Just
パブリッシャーは単一の値(の新しい値numberOfPeople
)を「ちょうど」受け取り、要求されたときにそれを出力します。onReceive
メソッドは、View
パブリッシャー(この場合Just
は先ほど作成したパブリッシャー)のサブスクライバーになります。サブスクライブすると、すぐにパブリッシャーから使用可能な値を要求されますnumberOfPeople
。その中の1つだけの新しい値があります。onReceive
、加入者が値を受信すると、指定されたクロージャを実行します。私たちの閉鎖は2つの方法のうちの1つを終わらせることができます。テキストがすでに数値のみの場合は、何もしません。フィルターされたテキストが異なる場合、@State
変数に書き込まれ、ループが再び開始されますが、今回は、プロパティを変更せずにクロージャーが実行されます。チェックアウト組み合わせる使い方詳細は。
Just
出版社の説明を追加しました。
Combine
and を使用する必要はありません。onReceive
次のコードも使用できます。
class Model: ObservableObject {
@Published var text : String = ""
}
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
TextField("enter a number ...", text: Binding(get: { self.model.text },
set: { self.model.text = $0.filter { "0123456789".contains($0) } }))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(Model())
}
}
残念ながら小さなちらつきもあるので、許可されていない文字を非常に短い時間で見ることもできます(私の目では、 Combine
)
別のアプローチとしては、TextFieldビューをラップし、2つの値を保持するビューを作成する方法があります。入力された文字列を保持するプライベート変数と、同等のDoubleを保持するバインド可能な値です。ユーザーが文字を入力するたびに、Doubleを更新しようとします。
基本的な実装は次のとおりです。
struct NumberEntryField : View {
@State private var enteredValue : String = ""
@Binding var value : Double
var body: some View {
return TextField("", text: $enteredValue)
.onReceive(Just(enteredValue)) { typedValue in
if let newValue = Double(typedValue) {
self.value = newValue
}
}.onAppear(perform:{self.enteredValue = "\(self.value)"})
}
}
次のように使用できます。
struct MyView : View {
@State var doubleValue : Double = 1.56
var body: some View {
return HStack {
Text("Numeric field:")
NumberEntryField(value: self.$doubleValue)
}
}
}
これは必要最低限の例です-不十分な入力や境界チェックなどの警告を表示する機能を追加したい場合があります...