Tôi mới sử dụng swiftUI và iOs, tôi đang cố gắng tạo trường nhập liệu sẽ chỉ chấp nhận số
TextField("Total number of people", text: $numOfPeople)
TextField cũng cho phép các ký tự chữ cái, làm cách nào để giới hạn người dùng chỉ nhập số?
Tôi mới sử dụng swiftUI và iOs, tôi đang cố gắng tạo trường nhập liệu sẽ chỉ chấp nhận số
TextField("Total number of people", text: $numOfPeople)
TextField cũng cho phép các ký tự chữ cái, làm cách nào để giới hạn người dùng chỉ nhập số?
Câu trả lời:
Bạn có thể đặt loại bàn phím trên TextField
đó sẽ giới hạn những gì mọi người có thể gõ.
TextField("Total number of people", text: $numOfPeople)
.keyboardType(.numberPad)
Tài liệu của Apple có thể được tìm thấy ở đây và bạn có thể xem danh sách tất cả các loại bàn phím được hỗ trợ tại đây .
Lưu ý: điều này sẽ không hoạt động trên iPad vì không có phím số cho iPad. Để có giải pháp tốt hơn, hãy kiểm tra giải pháp của John M bên dưới https://stackoverflow.com/a/58736068/5508175
Mặc dù hiển thị bàn phím số là bước đầu tiên tốt nhưng thực tế nó không ngăn được dữ liệu xấu được nhập vào:
Những gì bạn thực sự muốn làm là vệ sinh đầu vào, như thế này:
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
}
}
}
}
Bất cứ khi nào numOfPeople
thay đổi, các giá trị không phải là số được lọc ra và giá trị được lọc được so sánh để xem có numOfPeople
nên cập nhật lần thứ hai hay không, ghi đè đầu vào xấu bằng đầu vào được lọc.
Lưu ý rằng Just
nhà xuất bản yêu cầu bạn import Combine
.
BIÊN TẬP:
Để giải thích cho Just
nhà xuất bản, hãy xem xét phác thảo khái niệm sau đây về những gì xảy ra khi bạn thay đổi giá trị trong TextField
:
TextField
mất a Binding
đến a String
, khi nội dung của trường được thay đổi, nó cũng ghi thay đổi đó trở lại @State
biến.@State
thay đổi, SwiftUI sẽ tính toán lại thuộc body
tính của chế độ xem.body
tính toán, một Just
nhà xuất bản được tạo ra. Combine có rất nhiều nhà xuất bản khác nhau phát ra các giá trị theo thời gian, nhưng Just
nhà xuất bản chỉ lấy "chỉ" một giá trị duy nhất (giá trị mới numberOfPeople
) và phát ra khi được hỏi.onReceive
phương pháp làm cho một View
thuê bao với một nhà xuất bản, trong trường hợp này, các Just
nhà xuất bản, chúng tôi vừa tạo ra. Sau khi đăng ký, nó ngay lập tức yêu cầu bất kỳ giá trị có sẵn nào từ nhà xuất bản, trong đó chỉ có một giá trị mới numberOfPeople
.onReceive
thuê bao nhận được một giá trị, nó thực hiện việc đóng được chỉ định. Đóng cửa của chúng tôi có thể kết thúc một trong hai cách. Nếu văn bản chỉ là số, thì nó không làm gì cả. Nếu văn bản được lọc là khác nhau, nó được ghi vào @State
biến, bắt đầu lại vòng lặp, nhưng lần này việc đóng sẽ thực thi mà không sửa đổi bất kỳ thuộc tính nào.Kiểm tra bằng cách sử dụng Kết hợp để biết thêm.
Just
nhà xuất bản.
Bạn không cần sử dụng Combine
và onReceive
, bạn cũng có thể sử dụng mã này:
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())
}
}
Thật không may, cũng có một nhấp nháy nhỏ, vì vậy bạn cũng có thể thấy các ký tự không được phép trong một thời gian rất ngắn (trong mắt tôi ngắn hơn một chút như cách với Combine
)
Một cách tiếp cận khác có lẽ là tạo Chế độ xem bao bọc khung nhìn TextField và giữ hai giá trị: var riêng giữ Chuỗi đã nhập và giá trị ràng buộc giữ tương đương Double. Mỗi lần người dùng nhập một ký tự, nó sẽ cố cập nhật Double.
Đây là một triển khai cơ bản:
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)"})
}
}
Bạn có thể sử dụng nó như thế này:
struct MyView : View {
@State var doubleValue : Double = 1.56
var body: some View {
return HStack {
Text("Numeric field:")
NumberEntryField(value: self.$doubleValue)
}
}
}
Đây là một ví dụ cơ bản - bạn có thể muốn thêm chức năng để hiển thị cảnh báo cho đầu vào kém và có thể kiểm tra giới hạn, v.v ...