清除绑定文本到文本字段仍然显示文本字段中的文本
Clearing Binding text to textfield still shows text in textfield
我有一个 textField,旁边有一个清除文本的按钮。我的问题是 TextField View 只带有活页夹。因此,文本字段中的实际文本不会被删除,因为绑定不会重新加载视图。
我试图在示例中尽可能缩小范围:
struct ContentView: View {
@State var presentedView = false
@State var text: String = ""
var body: some View {
Button("Hello, world!") { presentedView = true }
.padding()
.sheet(isPresented: $presentedView, content: {
SomeView(viewModel: .init(textBinder: $text), text: $text)
})
}
}
struct SomeView: View {
let viewModel: ViewModel
@Binding var text: String
var body: some View {
HStack {
TextFieldTyped(text: $text)
Spacer()
Button("erase") {
$text.wrappedValue = ""
}
}
}
struct ViewModel {
let textBinder: Binding<String>
}
}
struct TextFieldTyped: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.becomeFirstResponder()
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: TextFieldTyped
init(_ textField: TextFieldTyped) {
self.parent = textField
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count ?? 0) == 1, string.isEmpty {
parent.text = string
} else if string.isEmpty, !(textField.text ?? "").isEmpty {
parent.text = String(textField.text?.dropLast() ?? "")
} else {
parent.text = (textField.text ?? "").isEmpty ? string : (textField.text ?? "") + string
}
return true
}
}
}
尝试下面的代码去掉无用的 ViewModel
,并在 updateUIView
中更新 text
:
struct ContentView: View {
@State var presentedView = false
@State var text: String = ""
var body: some View {
Button("Hello, world!") { presentedView = true }
.padding()
.sheet(isPresented: $presentedView, content: {
SomeView(text: $text)
})
}
}
struct SomeView: View {
@Binding var text: String
var body: some View {
HStack {
TextFieldTyped(text: $text)
Spacer()
Button("erase") {
text = "" // <--- here
}
}
}
}
struct TextFieldTyped: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.becomeFirstResponder()
uiView.text = text // <--- here
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: TextFieldTyped
init(_ textField: TextFieldTyped) {
self.parent = textField
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count ?? 0) == 1, string.isEmpty {
parent.text = string
} else if string.isEmpty, !(textField.text ?? "").isEmpty {
parent.text = String(textField.text?.dropLast() ?? "")
} else {
parent.text = (textField.text ?? "").isEmpty ? string : (textField.text ?? "") + string
}
return true
}
}
}
另一个答案非常好,但将相关变量拉出到它们自己的结构中也是个好主意,如 Data Essentials in SwiftUI (WWDC20) at 4:00 中的建议。这是我认为在您的情况下可以实现的方式:
struct SomeViewConfig {
var presented = false
var text: String = ""
mutating func present() {
presented = true
text = ""
}
}
struct ContentView2: View {
@State var someViewConfig = SomeViewConfig()
var body: some View {
Button("Hello, world!") { someViewConfig.present() }
.padding()
.sheet(isPresented: $someViewConfig.presented) {
SomeView(config: $someViewConfig)
}
}
}
struct SomeView: View {
@Binding var config: SomeViewConfig
var body: some View {
HStack {
TextFieldTyped(text: $config.text)
Spacer()
Button("erase") {
config.text = ""
}
}
}
}
我有一个 textField,旁边有一个清除文本的按钮。我的问题是 TextField View 只带有活页夹。因此,文本字段中的实际文本不会被删除,因为绑定不会重新加载视图。
我试图在示例中尽可能缩小范围:
struct ContentView: View {
@State var presentedView = false
@State var text: String = ""
var body: some View {
Button("Hello, world!") { presentedView = true }
.padding()
.sheet(isPresented: $presentedView, content: {
SomeView(viewModel: .init(textBinder: $text), text: $text)
})
}
}
struct SomeView: View {
let viewModel: ViewModel
@Binding var text: String
var body: some View {
HStack {
TextFieldTyped(text: $text)
Spacer()
Button("erase") {
$text.wrappedValue = ""
}
}
}
struct ViewModel {
let textBinder: Binding<String>
}
}
struct TextFieldTyped: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.becomeFirstResponder()
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: TextFieldTyped
init(_ textField: TextFieldTyped) {
self.parent = textField
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count ?? 0) == 1, string.isEmpty {
parent.text = string
} else if string.isEmpty, !(textField.text ?? "").isEmpty {
parent.text = String(textField.text?.dropLast() ?? "")
} else {
parent.text = (textField.text ?? "").isEmpty ? string : (textField.text ?? "") + string
}
return true
}
}
}
尝试下面的代码去掉无用的 ViewModel
,并在 updateUIView
中更新 text
:
struct ContentView: View {
@State var presentedView = false
@State var text: String = ""
var body: some View {
Button("Hello, world!") { presentedView = true }
.padding()
.sheet(isPresented: $presentedView, content: {
SomeView(text: $text)
})
}
}
struct SomeView: View {
@Binding var text: String
var body: some View {
HStack {
TextFieldTyped(text: $text)
Spacer()
Button("erase") {
text = "" // <--- here
}
}
}
}
struct TextFieldTyped: UIViewRepresentable {
@Binding var text: String
func makeUIView(context: Context) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.becomeFirstResponder()
uiView.text = text // <--- here
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: TextFieldTyped
init(_ textField: TextFieldTyped) {
self.parent = textField
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count ?? 0) == 1, string.isEmpty {
parent.text = string
} else if string.isEmpty, !(textField.text ?? "").isEmpty {
parent.text = String(textField.text?.dropLast() ?? "")
} else {
parent.text = (textField.text ?? "").isEmpty ? string : (textField.text ?? "") + string
}
return true
}
}
}
另一个答案非常好,但将相关变量拉出到它们自己的结构中也是个好主意,如 Data Essentials in SwiftUI (WWDC20) at 4:00 中的建议。这是我认为在您的情况下可以实现的方式:
struct SomeViewConfig {
var presented = false
var text: String = ""
mutating func present() {
presented = true
text = ""
}
}
struct ContentView2: View {
@State var someViewConfig = SomeViewConfig()
var body: some View {
Button("Hello, world!") { someViewConfig.present() }
.padding()
.sheet(isPresented: $someViewConfig.presented) {
SomeView(config: $someViewConfig)
}
}
}
struct SomeView: View {
@Binding var config: SomeViewConfig
var body: some View {
HStack {
TextFieldTyped(text: $config.text)
Spacer()
Button("erase") {
config.text = ""
}
}
}
}