在 SwiftUI 中创建电子邮件输入字段
Creating an Email Input Field in SwiftUI
我正在尝试在 SwiftUI 2 中创建一个仅允许输入特定字符的电子邮件输入字段。这里的代码是基于.
的一段代码
代码本身有效,但由于这是一个可重用的视图组件,我想提供一个文本 属性 从父视图的视图模型到 EmailTextField
,它在文本输入更改时更新。 ..
EmailTextField 视图:
import SwiftUI
import Combine
struct EmailTextField: View {
private class EmailTextFieldViewModel: ObservableObject {
@Published var text = String.Empty
private var subCancellable: AnyCancellable!
private var validCharSet = CharacterSet(charactersIn: "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+$!~&=#[]@")
init() {
subCancellable = $text.sink {
value in
/* Check if the new string contains any invalid characters. */
if value.rangeOfCharacter(from: self.validCharSet.inverted) != nil {
/* Clean the string (do this on the main thread to avoid overlapping with the current ContentView update cycle). */
DispatchQueue.main.async {
self.text = String(self.text.unicodeScalars.filter {
self.validCharSet.contains([=10=])
})
}
}
}
}
deinit {
subCancellable.cancel()
}
}
@ObservedObject private var viewModel = EmailTextFieldViewModel()
private let placeHolder: String
var body: some View {
TextField(placeHolder, text: $viewModel.text)
.keyboardType(.emailAddress)
.autocapitalization(.none)
.disableAutocorrection(true)
}
init(_ placeHolder: String = .Empty, text: Binding<String>) {
self.placeHolder = placeHolder
}
}
在父视图中,我尝试这样做:
var body: some View {
VStack {
EmailTextField("Email", text: $viewModel.email)
.onChange(of: viewModel.email, perform: onEmailInputChanged)
}
}
private func onEmailInputChanged(changedEmail: String) {
// Nothing happens here!
print("\(changedEmail)")
}
我需要如何更改 EmailTextField
代码才能将其视图模型中的 text
变量绑定到其构造函数中的 text: Binding<String>
参数?
这是您的(有点复杂的)代码的替代方法。我认为它更简单,提供可重用的 EmailInputView
和对 onEmailInputChanged
的调用,对我来说效果很好:
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var email = ""
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
EmailInputView(placeHolder: "Email", txt: $viewModel.email)
.onChange(of: viewModel.email, perform: onEmailInputChanged)
}
}
private func onEmailInputChanged(changedEmail: String) {
print("-----> in onEmailInputChanged: \(changedEmail) ")
}
}
struct EmailInputView: View {
var placeHolder: String = ""
@Binding var txt: String
var body: some View {
TextField(placeHolder, text: $txt)
.keyboardType(.emailAddress)
.onReceive(Just(txt)) { newValue in
let validString = newValue.filter { "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+$!~&=#[]@".contains([=10=]) }
if validString != newValue {
self.txt = validString
}
}
}
}
我正在尝试在 SwiftUI 2 中创建一个仅允许输入特定字符的电子邮件输入字段。这里的代码是基于
代码本身有效,但由于这是一个可重用的视图组件,我想提供一个文本 属性 从父视图的视图模型到 EmailTextField
,它在文本输入更改时更新。 ..
EmailTextField 视图:
import SwiftUI
import Combine
struct EmailTextField: View {
private class EmailTextFieldViewModel: ObservableObject {
@Published var text = String.Empty
private var subCancellable: AnyCancellable!
private var validCharSet = CharacterSet(charactersIn: "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+$!~&=#[]@")
init() {
subCancellable = $text.sink {
value in
/* Check if the new string contains any invalid characters. */
if value.rangeOfCharacter(from: self.validCharSet.inverted) != nil {
/* Clean the string (do this on the main thread to avoid overlapping with the current ContentView update cycle). */
DispatchQueue.main.async {
self.text = String(self.text.unicodeScalars.filter {
self.validCharSet.contains([=10=])
})
}
}
}
}
deinit {
subCancellable.cancel()
}
}
@ObservedObject private var viewModel = EmailTextFieldViewModel()
private let placeHolder: String
var body: some View {
TextField(placeHolder, text: $viewModel.text)
.keyboardType(.emailAddress)
.autocapitalization(.none)
.disableAutocorrection(true)
}
init(_ placeHolder: String = .Empty, text: Binding<String>) {
self.placeHolder = placeHolder
}
}
在父视图中,我尝试这样做:
var body: some View {
VStack {
EmailTextField("Email", text: $viewModel.email)
.onChange(of: viewModel.email, perform: onEmailInputChanged)
}
}
private func onEmailInputChanged(changedEmail: String) {
// Nothing happens here!
print("\(changedEmail)")
}
我需要如何更改 EmailTextField
代码才能将其视图模型中的 text
变量绑定到其构造函数中的 text: Binding<String>
参数?
这是您的(有点复杂的)代码的替代方法。我认为它更简单,提供可重用的 EmailInputView
和对 onEmailInputChanged
的调用,对我来说效果很好:
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var email = ""
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
EmailInputView(placeHolder: "Email", txt: $viewModel.email)
.onChange(of: viewModel.email, perform: onEmailInputChanged)
}
}
private func onEmailInputChanged(changedEmail: String) {
print("-----> in onEmailInputChanged: \(changedEmail) ")
}
}
struct EmailInputView: View {
var placeHolder: String = ""
@Binding var txt: String
var body: some View {
TextField(placeHolder, text: $txt)
.keyboardType(.emailAddress)
.onReceive(Just(txt)) { newValue in
let validString = newValue.filter { "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+$!~&=#[]@".contains([=10=]) }
if validString != newValue {
self.txt = validString
}
}
}
}