簡體   English   中英

如何通過單擊鍵盤上的返回按鈕來瀏覽 SwiftUI 文本字段?

[英]How to navigate through SwiftUI TextFields by clicking on return button from keyboard?

我正在使用 SwiftUI 的TextField View 主要是我有2個問題:

  1. 在 Swift 中,我們可以像這樣將 storyboard 中的 TextField 的Return Key(Text Input Traits)設置為Next ,對吧? 為此,在 SwiftUI 中使用哪個修飾符?

    在此處輸入圖像描述

  2. 我有兩個文本字段,當我從鍵盤單擊返回/下一個按鈕時,如何導航到下一個文本字段?

任何人都可以使用 SwiftUI(不是 UIKit)來幫助解決這個問題嗎? 或者執行此功能的任何其他替代方案?

要解決您的兩個問題,您需要使用SwiftUI中的UIKit 首先,您需要使用UIViewRepresentable自定義TextField 這是用於測試目的的示例代碼,盡管代碼不是那么優雅。 我敢打賭,會有更強大的解決方案。

  1. 在自定義的 TextFieldType 中,已經設置了 Keyboard 返回類型。
  2. 通過使用 object 綁定和委托方法textFieldShouldReturn ,View 可以通過更新綁定變量來聚焦鍵盤。

這是示例代碼:

import SwiftUI

struct KeyboardTypeView: View {
    @State var firstName = ""
    @State var lastName = ""
    @State var focused: [Bool] = [true, false]

    var body: some View {
        Form {
            Section(header: Text("Your Info")) {
                TextFieldTyped(keyboardType: .default, returnVal: .next, tag: 0, text: self.$firstName, isfocusAble: self.$focused)
                TextFieldTyped(keyboardType: .default, returnVal: .done, tag: 1, text: self.$lastName, isfocusAble: self.$focused)
                Text("Full Name :" + self.firstName + " " + self.lastName)
            }
        }
}
}



struct TextFieldTyped: UIViewRepresentable {
    let keyboardType: UIKeyboardType
    let returnVal: UIReturnKeyType
    let tag: Int
    @Binding var text: String
    @Binding var isfocusAble: [Bool]

    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField(frame: .zero)
        textField.keyboardType = self.keyboardType
        textField.returnKeyType = self.returnVal
        textField.tag = self.tag
        textField.delegate = context.coordinator
        textField.autocorrectionType = .no

        return textField
    }

    func updateUIView(_ uiView: UITextField, context: Context) {
        if isfocusAble[tag] {
            uiView.becomeFirstResponder()
        } else {
            uiView.resignFirstResponder()
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: TextFieldTyped

        init(_ textField: TextFieldTyped) {
            self.parent = textField
        }

        func updatefocus(textfield: UITextField) {
            textfield.becomeFirstResponder()
        }

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

            if parent.tag == 0 {
                parent.isfocusAble = [false, true]
                parent.text = textField.text ?? ""
            } else if parent.tag == 1 {
                parent.isfocusAble = [false, false]
                parent.text = textField.text ?? ""
         }
        return true
        }

    }
}

Output: 在此處輸入圖像描述

iOS 15.0+

macOS 12.0+、Mac Catalyst 15.0+、tvOS 15.0+、watchOS 8.0+

使用submitLabel(_:)視圖修飾符,為視圖設置提交 label。 它采用SubmitLabel中指定的預定義案例

使用.next 它定義了一個帶有“Next”文本的提交 label 。

使用onFocus(_:)查找修改后的視圖層次結構(在本例中為TextField )何時失去焦點。 完成后,將焦點放在下一個視圖( SecureField

struct LoginForm: View {
    enum Field: Hashable {
        case usernameField
        case passwordField
    }
    
    @State private var username = ""
    @State private var password = ""
    @FocusState private var focusedField: Field?
    
    var body: some View {
        Form {
            TextField("Username", text: $username)
                .focused($focusedField, equals: .usernameField)
                .submitLabel(.next)
                .onFocus { isFocused in
                    if (!isFocused) {
                        focusedField = .passwordField
                    }
                }
            
            SecureField("Password", text: $password)
                .focused($focusedField, equals: .passwordField)
                .submitLabel(.done)
        }
    }
}

你不能,SwiftUI 中還沒有響應者鏈的概念。 您不能以編程方式啟動對任何View的關注,因為它們實際上並不是視圖本身,而只是描述應如何設置視圖的結構。 我猜它最終可能會通過EnvironmentValues暴露出來(如行截斷、自動更正等),但它目前不存在。

基於 Razib Mollick 的回答和https://www.hackingwithswift.com/forums/100-days-of-swiftui/jump-focus-between-a-series-of-textfields-pin-code-style-entry-widget/ 765

我為文本字段數組提出了以下實現。

struct NextLineTextField: UIViewRepresentable {
@Binding var text: String
@Binding var selectedField: Int

var tag: Int
var keyboardType: UIKeyboardType = .asciiCapable
var returnKey: UIReturnKeyType = .next

func makeUIView(context: UIViewRepresentableContext<NextLineTextField>) -> UITextField {
    let textField = UITextField(frame: .zero)
    textField.delegate = context.coordinator
    textField.keyboardType = keyboardType
    textField.returnKeyType = returnKey
    textField.tag = tag
    return textField
}

func makeCoordinator() -> NextLineTextField.Coordinator {
    return Coordinator(text: $text)
}

func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<NextLineTextField>) {
    uiView.text = text
    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
    var newSelection: (Int) -> () = { _ in }

    init(text: Binding<String>) {
        _text = text
    }

    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
    }
  }
}

然后將表單元素設為

class FieldElement: ObservableObject, Identifiable {
var id = UUID()
var title = ""
@Published var value = ""
var keyboard: UIKeyboardType = .asciiCapable
var returnType: UIReturnKeyType = .next

init(title: String, value: String = "", keyboard: UIKeyboardType = 
    .asciiCapable, returnType: UIReturnKeyType = .next) {
    self.title = title
    self.value = value
    self.keyboard = keyboard
    self.returnType = returnType
  }
}

並為實施

struct FormView: View {

@State var formElements: [FieldElement] = [
    FieldElement(title: "Name"),
    FieldElement(title: "Address"),
    FieldElement(title: "Phone Number"),
    FieldElement(title: "Email Address", keyboard: .emailAddress, returnType: 
.done),
]

@State var selectedField = 0

var body: some View {
    VStack(alignment: .leading) {
        ForEach(Array(zip(formElements.indices, formElements)), id: \.0) { 
        index, element in
            VStack(alignment: .leading, spacing: 0) {
                Text(element.title)

                NextLineTextField(text: self.$formElements[index].value,
                    selectedField: self.$selectedField,
                    tag: index,
                    keyboardType: element.keyboard,
                    returnKey: element.returnType)
                    .frame(height: 35)
                    .frame(maxWidth: .infinity)
                    .overlay(
                        RoundedRectangle(cornerRadius: 8)
                            .stroke(Color.gray.opacity(0.5), lineWidth: 0.7)
                    )
            }.padding(.bottom, 4)
        }

        Button(action: {
            print(self.formElements.map({ $0.value }))
        }) {
            Text("Print Entered Values")
                .foregroundColor(Color.white)
                .font(.body)
                .padding()
        }.frame(height: 50)
            .background(Color.green)
            .cornerRadius(8)
            .padding(.vertical, 10)
        Spacer()
    }.padding()
  }
}

如果這很難導航,請隨時查看https://github.com/prakshapan/Utilities/blob/master/FormView.swift

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM