Swift:设置 isSecureTextEntry 后 TextField 自行清除
Swift: TextField clearing itself after isSecureTextEntry set
我在 SwiftUI 中实现自定义文本字段时遇到一些困难。我正在尝试创建一个密码字段,但是我不得不深入研究 UIKit,因为我需要在字段聚焦时做出反应,并且(与 SwiftUI 中的标准 TextField 不同)没有 onEditingChanged
闭包安全字段。
所以我有以下内容:
struct PasswordField: UIViewRepresentable {
@ObservedObject var viewModel: TextFieldFloatingWithBorderViewModel
func makeUIView(context: UIViewRepresentableContext<PasswordField>) -> UITextField {
let tf = UITextField(frame: .zero)
tf.isUserInteractionEnabled = true
tf.delegate = context.coordinator
return tf
}
func makeCoordinator() -> PasswordField.Coordinator {
return Coordinator(viewModel: viewModel)
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = viewModel.text
uiView.isSecureTextEntry = !viewModel.isRevealed
}
class Coordinator: NSObject, UITextFieldDelegate {
@ObservedObject var viewModel: TextFieldFloatingWithBorderViewModel
init(viewModel: TextFieldFloatingWithBorderViewModel) {
self.viewModel = viewModel
}
func textFieldDidChangeSelection(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.text = textField.text ?? ""
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.isFocused = true
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.isFocused = false
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
}
}
然后我们在 SwiftUI 视图中如下声明此字段:
HStack {
PasswordField(viewModel: viewModel)
Button(action: {
viewModel.toggleReveal()
}) {
viewModel.revealIcon
.foregroundColor(viewModel.isFocused ? .blue : viewModel.hasWarning ? .red: .gray)
}
}
在 TextFieldFloatingWithBorderViewModel viewModel 中,我们有一个 Published var isRevealed
,然后在点击按钮时调用以下方法:
func toggleReveal() {
isRevealed.toggle()
}
因为在密码字段中我们有:
uiView.isSecureTextEntry = !viewModel.isRevealed
这会在安全视图(即用点屏蔽的输入)和标准视图之间切换密码字段。这运行良好,除了当用户切换回隐藏并继续键入密码时被擦除:
我不明白为什么要在这里擦除密码,而且只有当密码从不安全变为安全时(而不是相反)
您已经有 @FocusState
了。您可以像使用任何状态变量一样使用它。这是我在 TextField
上放置黄色背景并使用 @FocusState
变量有条件地控制它的一些代码:
struct HighlightWhenFocused: View {
@State private var password: String = ""
@FocusState var passwordFocused: Bool
var body: some View {
PasswordView(password: $password)
.focused($passwordFocused)
.background(
Color.yellow
.opacity(passwordFocused ? 1 : 0)
)
}
}
struct PasswordView: View {
@Binding var password: String
@State private var secured = true
var body: some View {
HStack{
Text("Password:")
if secured{
SecureField("",text:$password)
}
else{
TextField("",text: $password)
}
Button {
secured.toggle()
} label: {
Image(systemName: secured ? "eye.slash" : "eye")
}
.buttonStyle(BorderlessButtonStyle())
}
}
}
对其进行编辑,使其成为安全的密码解决方案。请注意,当您在 viewable/non-viewable 之间切换时,这些字段会失去焦点,因为您点击了它们之外的区域。
我在 SwiftUI 中实现自定义文本字段时遇到一些困难。我正在尝试创建一个密码字段,但是我不得不深入研究 UIKit,因为我需要在字段聚焦时做出反应,并且(与 SwiftUI 中的标准 TextField 不同)没有 onEditingChanged
闭包安全字段。
所以我有以下内容:
struct PasswordField: UIViewRepresentable {
@ObservedObject var viewModel: TextFieldFloatingWithBorderViewModel
func makeUIView(context: UIViewRepresentableContext<PasswordField>) -> UITextField {
let tf = UITextField(frame: .zero)
tf.isUserInteractionEnabled = true
tf.delegate = context.coordinator
return tf
}
func makeCoordinator() -> PasswordField.Coordinator {
return Coordinator(viewModel: viewModel)
}
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = viewModel.text
uiView.isSecureTextEntry = !viewModel.isRevealed
}
class Coordinator: NSObject, UITextFieldDelegate {
@ObservedObject var viewModel: TextFieldFloatingWithBorderViewModel
init(viewModel: TextFieldFloatingWithBorderViewModel) {
self.viewModel = viewModel
}
func textFieldDidChangeSelection(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.text = textField.text ?? ""
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.isFocused = true
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
DispatchQueue.main.async {
self.viewModel.isFocused = false
}
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
}
}
然后我们在 SwiftUI 视图中如下声明此字段:
HStack {
PasswordField(viewModel: viewModel)
Button(action: {
viewModel.toggleReveal()
}) {
viewModel.revealIcon
.foregroundColor(viewModel.isFocused ? .blue : viewModel.hasWarning ? .red: .gray)
}
}
在 TextFieldFloatingWithBorderViewModel viewModel 中,我们有一个 Published var isRevealed
,然后在点击按钮时调用以下方法:
func toggleReveal() {
isRevealed.toggle()
}
因为在密码字段中我们有:
uiView.isSecureTextEntry = !viewModel.isRevealed
这会在安全视图(即用点屏蔽的输入)和标准视图之间切换密码字段。这运行良好,除了当用户切换回隐藏并继续键入密码时被擦除:
我不明白为什么要在这里擦除密码,而且只有当密码从不安全变为安全时(而不是相反)
您已经有 @FocusState
了。您可以像使用任何状态变量一样使用它。这是我在 TextField
上放置黄色背景并使用 @FocusState
变量有条件地控制它的一些代码:
struct HighlightWhenFocused: View {
@State private var password: String = ""
@FocusState var passwordFocused: Bool
var body: some View {
PasswordView(password: $password)
.focused($passwordFocused)
.background(
Color.yellow
.opacity(passwordFocused ? 1 : 0)
)
}
}
struct PasswordView: View {
@Binding var password: String
@State private var secured = true
var body: some View {
HStack{
Text("Password:")
if secured{
SecureField("",text:$password)
}
else{
TextField("",text: $password)
}
Button {
secured.toggle()
} label: {
Image(systemName: secured ? "eye.slash" : "eye")
}
.buttonStyle(BorderlessButtonStyle())
}
}
}
对其进行编辑,使其成为安全的密码解决方案。请注意,当您在 viewable/non-viewable 之间切换时,这些字段会失去焦点,因为您点击了它们之外的区域。