SwiftUI 是否有像 Cocoa 的 nextKeyView 这样的东西,以便我可以指定当我点击 Tab 时 TextViews 获取光标的确切顺序? [英] Does SwiftUI have something like Cocoa's nextKeyView, so that I can specify the exact order TextViews get a cursor when I hit tab?

查看:47
本文介绍了SwiftUI 是否有像 Cocoa 的 nextKeyView 这样的东西,以便我可以指定当我点击 Tab 时 TextViews 获取光标的确切顺序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下,我有 6 个 TextFields 排列在一个 3 列 2 行的网格中.我们将通过它们在此网格中的 X、Y 位置来引用它们,从左上角 TextField 的 1,1 和右下角的 3,2 开始.

Imagine that I have 6 TextFields arranged in a grid with 3 columns and 2 rows. We'll refer to them by their X,Y position in this grid, starting with 1,1 in the upper left TextField, and 3,2 in the lower right corner.

当我运行这个程序时,我将光标放在 TextField 1,1 并输入一个值.我点击 Tab 键,光标转到 2,1;然后到 3,1;然后到 1,2;然后 2,2;最后到 3,2.

When I run this program, I put the cursor in TextField 1,1 and enter a value. I hit tab and the cursor goes to 2,1; then to 3,1; then to 1,2; then 2,2; and finally to 3,2.

光标在第一行水平移动,然后是第二行,依此类推.

The cursor is marching horizontally across the first row, then the second, and so on.

不过,我需要更改该顺序.

I need to change that order, though.

我需要它沿着第 1 列前进,然后移动到第 2 列,然后进入第 3 列.

I need it to march down column 1, before moving to column 2, and then on to column 3.

在 Cocoa 编程中,您可以使用 nextKeyView 指定顺序.

In Cocoa programming, you can specify the order using nextKeyView.

SwiftUI 中是否有类似的东西?

Is there anything similar in SwiftUI?

我希望我可以像下面那样将它们分组到 VStack 中并获得我想要的行为,但它不起作用.我也尝试将列对放在 Group{...} 中,但它不起作用.

I was hoping I could group them in VStacks like below and get the behavior I wanted, but it doesn't work. I also tried putting the column-pairs in Group{...} but it doesn't work.

struct ContentView: View {
@State private var oneone = ""
@State private var onetwo = ""
@State private var twoone = ""
@State private var twotwo = ""
@State private var threeone = ""
@State private var threetwo = ""

var body: some View {
    HStack {
        VStack {
            TextField("1,1", text: $oneone)

            TextField("1,2", text: $onetwo)
        }
        
        VStack {
            TextField("2,1", text: $twoone)

            TextField("2,2", text: $twotwo)
        }

        VStack {
            TextField("3,1", text: $threeone)

            TextField("3,2", text: $threetwo)

        }
    }
}

}

推荐答案

SwiftUI 尚未内置此功能,但 Swift 内置了.要在 SwiftUI 中执行此操作,请创建一个符合 UIViewRepresentable 的自定义文本字段,以在文本字段中使用 becomeFirstResponder 功能.这是我在项目中的做法.这个例子有几个你可能不需要的可选变量.随意调整它以适合您.

SwiftUI doesn't have this built in yet, but Swift does. To do it in SwiftUI, create a custom text field that conforms to UIViewRepresentable to use the becomeFirstResponder functionality in a text field. Here's how I did it in my project. This example has several optional variables you may not need. Feel free to tweak it to work for you.

struct CustomTextField: UIViewRepresentable
{
  @Binding var text: String
  @Binding var selectedField: Int
  @Binding var secure: Bool // Optional
  var placeholder: String = ""
  
  var tag: Int
  var keyboardType: UIKeyboardType = .asciiCapable // Optional
  var returnKey: UIReturnKeyType = .next // Optional
  var correctionType: UITextAutocorrectionType = .default // Optional
  var capitalizationType: UITextAutocapitalizationType = .sentences // Optional
  
  func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField
  {
    let textField = UITextField(frame: .zero)
    textField.delegate = context.coordinator
    textField.keyboardType = keyboardType
    textField.returnKeyType = returnKey
    textField.autocorrectionType = correctionType
    textField.autocapitalizationType = capitalizationType
    textField.tag = tag
    textField.isSecureTextEntry = secure
    textField.placeholder = placeholder
    return textField
  }
  
  func makeCoordinator() -> CustomTextField.Coordinator
  {
    return Coordinator(text: $text, secure: $secure)
  }
  
  func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>)
  {
    uiView.text = text
    uiView.isSecureTextEntry = secure
    context.coordinator.newSelection = { newSelection in
      DispatchQueue.main.async {
        self.selectedField = newSelection
      }
    }
    
    if uiView.tag == self.selectedField
    {
      uiView.becomeFirstResponder()
    }
  }
  
  class Coordinator: NSObject, UITextFieldDelegate
  {
    @Binding var text: String
    @Binding var secure: Bool
    var newSelection: (Int) -> () = { _ in }
    
    init(text: Binding<String>, secure: Binding<Bool>)
    {
      _text = text
      _secure = secure
    }
    
    func textFieldDidChangeSelection(_ textField: UITextField)
    {
      DispatchQueue.main.async {
        self.text = textField.text ?? ""
      }
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField)
    {
      self.newSelection(textField.tag)
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool
    {
      if textField.returnKeyType == .done
      {
        textField.resignFirstResponder()
      }
      else
      {
        self.newSelection(textField.tag + 1)
      }
      return true
    }
  }
}

然后,在带有文本字段的视图中,为每个字段分配不同的标签,指示所需的顺序.

Then, in the view with the text fields, assign each one a different tag, indicating the desired order.

struct ContentView: View {
    @State private var oneOne = ""
    @State private var oneTwo = ""
    @State private var twoOne = ""
    @State private var twoTwo = ""
    @State private var threeOne = ""
    @State private var threeTwo = ""
    @State private var selectedField: Int = 0
    @State private var fieldsSecure: Bool = false

var body: some View {
    HStack {
        VStack {
            CustomTextField(
             text: $oneOne, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "1, 1", 
             tag: 1, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)

            CustomTextField(
             text: $oneTwo, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "1, 2", 
             tag: 4, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)
        }
        
        VStack {
            CustomTextField(
             text: $twoOne, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "2, 1", 
             tag: 2, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)

            CustomTextField(
             text: $twoTwo, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "2, 2", 
             tag: 5, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)
        }

        VStack {
            CustomTextField(
             text: $threeOne, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "3, 1", 
             tag: 3, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)

            CustomTextField(
             text: $threeTwo, 
             selectedField: $selectedField, 
             secure: $fieldsSecure, 
             placeholder: "3, 2", 
             tag: 6, 
             keyboardType: .asciiCapable, 
             returnKey: .done, 
             correctionType: .yes, 
             capitalizationType: .words)
        }
    }
}

这篇关于SwiftUI 是否有像 Cocoa 的 nextKeyView 这样的东西,以便我可以指定当我点击 Tab 时 TextViews 获取光标的确切顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆