如何从 SwiftUI 的 TextField 中删除特殊字符
How to remove special characters from the `TextField` in SwiftUI
我需要在我的表单中应用一些验证,例如删除 特殊字符,仅接受 数字,字母、字母数字,并且只有字符串的特定 长度。
我有很多文本字段,在我的应用程序的很多地方。所以我正在创建绑定扩展,并尝试在编辑时应用条件。
这些 filters/conditions 用于 @State
、@Published
和 @Binding
变量。
这是我的代码:
struct ContentView: View {
@State var name = ""
var body: some View {
InputField(text: $name)
}
}
struct InputField: View {
@Binding var text: String
var body: some View {
VStack {
TextField("Name here...", text: $text.limit(6).alphaNumeric)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
}.padding()
}
}
extension Binding where Value == String {
var alphaNumeric: Binding<String> {
Binding<String>(get: { self.wrappedValue },
set: {
self.wrappedValue = [=10=].trimmingCharacters(in: CharacterSet.alphanumerics.inverted)})
}
func limit(_ length: Int) -> Binding<String> {
Binding<String>(get: { self.wrappedValue },
set: {
print([=10=].prefix(length))
self.wrappedValue = String([=10=].prefix(length))
})
}
}
在上面的代码 $text.limit(6).alphaNumeric
中,我试图将 长度 限制为 6 个字符 并且只允许alphaNumeric 字符串。
您可以使用 .onChange(of: )
。也应该适用于@Binding 等
@State private var inputText = ""
let maxCount = 20
var body: some View {
TextField("Input", text: $inputText)
.padding()
.background(.gray.opacity(0.1))
.padding()
.onChange(of: inputText) { _ in
// check character set
var checked = inputText.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
// check length
checked = String(checked.prefix(maxCount)) // regards to Leo Dabus
inputText = checked
}
}
自定义带有检查的 TextField 怎么样,而不是搞乱 Binding Wrapper 本身:
(使用 OP 的完整代码来证明绑定有效)
struct ContentView: View {
@State var name = ""
@State var number = ""
var body: some View {
InputField(text: $name, number: $number)
}
}
struct InputField: View {
@Binding var text: String
@Binding var number: String
var body: some View {
VStack {
TextFieldWithCheck("Name here...", text: $text, limit: 15, allowed: .alphanumerics)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
TextFieldWithCheck("Phone no here...", text: $number, limit: 9, allowed: .decimalDigits)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
}.padding()
}
}
// here is the custom TextField itself
struct TextFieldWithCheck: View {
let label: LocalizedStringKey
@Binding var text: String
let limit: Int
let allowed: CharacterSet
init(_ label: LocalizedStringKey, text: Binding<String>, limit: Int = Int.max, allowed: CharacterSet = .alphanumerics) {
self.label = label
self._text = Binding(projectedValue: text)
self.limit = limit
self.allowed = allowed
}
var body: some View {
TextField(label, text: $text)
.onChange(of: text) { _ in
// all credits to Leo Dabus:
text = String(text.prefix(limit).unicodeScalars.filter(allowed.contains))
}
}
}
我需要在我的表单中应用一些验证,例如删除 特殊字符,仅接受 数字,字母、字母数字,并且只有字符串的特定 长度。
我有很多文本字段,在我的应用程序的很多地方。所以我正在创建绑定扩展,并尝试在编辑时应用条件。
这些 filters/conditions 用于 @State
、@Published
和 @Binding
变量。
这是我的代码:
struct ContentView: View {
@State var name = ""
var body: some View {
InputField(text: $name)
}
}
struct InputField: View {
@Binding var text: String
var body: some View {
VStack {
TextField("Name here...", text: $text.limit(6).alphaNumeric)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
}.padding()
}
}
extension Binding where Value == String {
var alphaNumeric: Binding<String> {
Binding<String>(get: { self.wrappedValue },
set: {
self.wrappedValue = [=10=].trimmingCharacters(in: CharacterSet.alphanumerics.inverted)})
}
func limit(_ length: Int) -> Binding<String> {
Binding<String>(get: { self.wrappedValue },
set: {
print([=10=].prefix(length))
self.wrappedValue = String([=10=].prefix(length))
})
}
}
在上面的代码 $text.limit(6).alphaNumeric
中,我试图将 长度 限制为 6 个字符 并且只允许alphaNumeric 字符串。
您可以使用 .onChange(of: )
。也应该适用于@Binding 等
@State private var inputText = ""
let maxCount = 20
var body: some View {
TextField("Input", text: $inputText)
.padding()
.background(.gray.opacity(0.1))
.padding()
.onChange(of: inputText) { _ in
// check character set
var checked = inputText.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
// check length
checked = String(checked.prefix(maxCount)) // regards to Leo Dabus
inputText = checked
}
}
自定义带有检查的 TextField 怎么样,而不是搞乱 Binding Wrapper 本身: (使用 OP 的完整代码来证明绑定有效)
struct ContentView: View {
@State var name = ""
@State var number = ""
var body: some View {
InputField(text: $name, number: $number)
}
}
struct InputField: View {
@Binding var text: String
@Binding var number: String
var body: some View {
VStack {
TextFieldWithCheck("Name here...", text: $text, limit: 15, allowed: .alphanumerics)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
TextFieldWithCheck("Phone no here...", text: $number, limit: 9, allowed: .decimalDigits)
.frame(maxWidth: .infinity, minHeight: 48, alignment: .leading)
}.padding()
}
}
// here is the custom TextField itself
struct TextFieldWithCheck: View {
let label: LocalizedStringKey
@Binding var text: String
let limit: Int
let allowed: CharacterSet
init(_ label: LocalizedStringKey, text: Binding<String>, limit: Int = Int.max, allowed: CharacterSet = .alphanumerics) {
self.label = label
self._text = Binding(projectedValue: text)
self.limit = limit
self.allowed = allowed
}
var body: some View {
TextField(label, text: $text)
.onChange(of: text) { _ in
// all credits to Leo Dabus:
text = String(text.prefix(limit).unicodeScalars.filter(allowed.contains))
}
}
}