swift - 在 SwiftUI 中以编程方式自动聚焦 TextField

标签 swift xcode modal-dialog textfield swiftui

我正在使用模式将名称添加到列表中。当显示模式时,我想自动聚焦 TextField,如下所示:

Preview

我还没有找到任何合适的解决方案。

为了做到这一点,是否已经在 SwiftUI 中实现了任何东西?

谢谢你的帮助。

var modal: some View {
        NavigationView{
            VStack{
                HStack{
                    Spacer()
                    TextField("Name", text: $inputText) // autofocus this!
                        .textFieldStyle(DefaultTextFieldStyle())
                        .padding()
                        .font(.system(size: 25))
                        // something like .focus() ??
                    Spacer()
                }
                Button(action: {
                    if self.inputText != ""{
                        self.players.append(Player(name: self.inputText))
                        self.inputText = ""
                        self.isModal = false
                    }
                }, label: {
                    HStack{
                        Text("Add \(inputText)")
                        Image(systemName: "plus")
                    }
                        .font(.system(size: 20))
                })
                    .padding()
                    .foregroundColor(.white)
                    .background(Color.blue)
                    .cornerRadius(10)
                Spacer()
            }
                .navigationBarTitle("New Player")
                .navigationBarItems(trailing: Button(action: {self.isModal=false}, label: {Text("Cancel").font(.system(size: 20))}))
                .padding()
        }
    }

最佳答案

由于 Responder Chain 不是通过 SwiftUI 呈现的,所以我们必须使用 UIViewRepresentable 来消费它。
我已经做了一个变通方法,它的工作方式与我们使用 UIKit 的方式类似。

 struct CustomTextField: UIViewRepresentable {

   class Coordinator: NSObject, UITextFieldDelegate {

      @Binding var text: String
      @Binding var nextResponder : Bool?
      @Binding var isResponder : Bool?

      init(text: Binding<String>,nextResponder : Binding<Bool?> , isResponder : Binding<Bool?>) {
        _text = text
        _isResponder = isResponder
        _nextResponder = nextResponder
      }

      func textFieldDidChangeSelection(_ textField: UITextField) {
        text = textField.text ?? ""
      }
    
      func textFieldDidBeginEditing(_ textField: UITextField) {
         DispatchQueue.main.async {
             self.isResponder = true
         }
      }
    
      func textFieldDidEndEditing(_ textField: UITextField) {
         DispatchQueue.main.async {
             self.isResponder = false
             if self.nextResponder != nil {
                 self.nextResponder = true
             }
         }
      }
  }

  @Binding var text: String
  @Binding var nextResponder : Bool?
  @Binding var isResponder : Bool?

  var isSecured : Bool = false
  var keyboard : UIKeyboardType

  func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
      let textField = UITextField(frame: .zero)
      textField.isSecureTextEntry = isSecured
      textField.autocapitalizationType = .none
      textField.autocorrectionType = .no
      textField.keyboardType = keyboard
      textField.delegate = context.coordinator
      return textField
  }

  func makeCoordinator() -> CustomTextField.Coordinator {
      return Coordinator(text: $text, nextResponder: $nextResponder, isResponder: $isResponder)
  }

  func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
       uiView.text = text
       if isResponder ?? false {
           uiView.becomeFirstResponder()
       }
  }

}
你可以像这样使用这个组件......
struct ContentView : View {

@State private var username =  ""
@State private var password =  ""

// set true , if you want to focus it initially, and set false if you want to focus it by tapping on it.
@State private var isUsernameFirstResponder : Bool? = true
@State private var isPasswordFirstResponder : Bool? =  false


  var body : some View {
    VStack(alignment: .center) {
        
        CustomTextField(text: $username,
                        nextResponder: $isPasswordFirstResponder,
                        isResponder: $isUsernameFirstResponder,
                        isSecured: false,
                        keyboard: .default)
        
        // assigning the next responder to nil , as this will be last textfield on the view.
        CustomTextField(text: $password,
                        nextResponder: .constant(nil),
                        isResponder: $isPasswordFirstResponder,
                        isSecured: true,
                        keyboard: .default)
    }
    .padding(.horizontal, 50)
  }
}
这里 isResponder 是将响应者分配给当前文本字段,而 nextResponder 是做出第一个响应,因为当前文本字段将其辞职。

关于swift - 在 SwiftUI 中以编程方式自动聚焦 TextField,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58311022/

相关文章:

ios - 当我购买一个级别的应用程序内购买时,另一个级别也会解锁......为什么会发生这种情况?

ios - 有没有更好的方法从字典中读取元素?

ios - 模拟器与 iPad 上部署的差异

jquery - 如何禁用 jquery 对话框按钮

ios - 如何更改 UINavigationBar 的字体和颜色?

arrays - Swift 3 - 存储值、元组、数组等的正确方法?

xcode - 我可以用于 UILabel 的 swift 基本字体是什么

ios - Xcode 的 Profiler 不显示符号名称

javascript - 如何在当前滚动位置垂直居中对话框

angularjs - 向AngularJS Modal UI.Bootstrap模态添加其他类