【问题标题】:Is it possible to change "return" key to "done" on keyboard with SwiftUI?是否可以使用 SwiftUI 将键盘上的“返回”键更改为“完成”?
【发布时间】:2020-01-31 17:20:37
【问题描述】:

在 SwiftUI 中为 TextField 打开键盘时,我没有找到任何链接或指南来将“返回”键更改为“完成”。

现在可以不自定义 UITextField 吗?

【问题讨论】:

标签: swift swiftui


【解决方案1】:

iOS 15

您可以使用一个名为 submitLabel 的简单修饰符更改每个 textField 的返回键,该修饰符采用返回键类型:

来自 WWDC21 的图片

此外,如您所见,您可以使用回调来处理返回键按下操作,就像 .onSubmit 修饰符可以访问的旧 textFieldShouldReturn 函数一样。

⚠️ 似乎 Xcode 13 beta 1 中存在一个错误,导致此修饰符在某些情况下无法正常工作。

【讨论】:

  • 它对你有用吗?它不适合我,我想知道是否有错误或什么......
  • 你检查过 iOS 15 吗?
  • 好的,我只是发现它在工作表中不起作用。没有工作表,它工作正常。
【解决方案2】:

更新

这不再是一个好的解决方案。在 iOS 15 中,您现在可以添加 .submitLabel(.done) 修饰符。有关详细信息,请参阅 Mojtaba 的回答。


旧答案

我发现最好的方法是将包 Introspect 添加到您的项目中。

这样做后,在项目文件的任何位置添加import Introspect

然后将他们的视图修饰符之一添加到您的Textfield 以实现您想要的。我相信这就是你想要的 ⤵

.introspectTextField { textfield in
  textfield.returnKeyType = .done
}

内省是做什么的?

它公开了 UIKit 以在 SwiftUI 中使用。因此,您在上面看到的 Textfield 对象可以访问所有 UITextfield 功能!虽然这是一个软件包,但请注意它可能会在未来损坏,但目前这是一个不错的选择。

这很好,因为它使您不必为每个视图制作自己的 UIKit 包装器?

【讨论】:

  • 这是一个很棒的 pod,谢谢分享。我真的不喜欢这样的解决方法,我认为这是一种天才的方法,直到这些东西可以更自然地在 SwiftUI 中访问。
  • 这应该被选为正确答案。
【解决方案3】:

如果有人想在 UIViewRepresentable 中包装 UITextField,那么我有一些代码可以分享:

struct CustomTextField: UIViewRepresentable {

    let tag: Int
    let placeholder: String
    let keyboardType: UIKeyboardType
    let returnVal: UIReturnKeyType

    @Binding var text: String
    @Binding var activeFieldTag: Int?
    var totalFields: Int = 0
    @Binding var isSecureTextEntry: Bool
    var textColor: UIColor = .pureWhite
    var font: UIFont = .nexaBold13
    var placeholderTextColor: UIColor = .pureWhite
    var placeholderFont: UIFont = .nexaLight13
    var onEditingChanged: (Bool) -> Void = { _ in }

    var lastActiveFieldTag: Int? {

        // Return, if no active field
        // (It also means textFieldShouldReturn not called yet OR called for last field)
        guard let activeFieldTag = activeFieldTag else {
            return nil
        }
        // Return previous field
        if activeFieldTag > 0 {
            return activeFieldTag - 1
        }
        // Return, if no previous field
        return nil
    }

    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField(frame: .zero)
        textField.keyboardType = self.keyboardType
        textField.returnKeyType = self.returnVal
        textField.tag = self.tag
        textField.textColor = textColor
        textField.font = font
        textField.attributedPlaceholder = NSAttributedString(
            string: self.placeholder,
            attributes: [
                NSAttributedString.Key.foregroundColor: placeholderTextColor,
                NSAttributedString.Key.font: placeholderFont,
            ]
        )
        textField.delegate = context.coordinator
        textField.autocorrectionType = .no
        textField.isSecureTextEntry = isSecureTextEntry
        return textField
    }

    func updateUIView(_ textField: UITextField, context: Context) {
        if textField.text != self.text {
            textField.text = self.text
        }
        handleFirstResponder(textField)
        if textField.isSecureTextEntry != isSecureTextEntry {
            textField.isSecureTextEntry = isSecureTextEntry
        }
    }

    func handleFirstResponder(_ textField: UITextField) {

        // return if field is neither active nor last-active
        if tag != lastActiveFieldTag && tag != activeFieldTag {
            return
        }

        // return if field is already active
        if lastActiveFieldTag == activeFieldTag {
            return
        }

        // It creates problem in UI when we press the next button too fast and continuously on keyboard
        //        // Remove focus from last active field
        //        if lastActiveFieldTag == tag {
        //            uiView.removeFocus()
        //            return
        //        }

        // Give focus to active field
        if activeFieldTag == tag {
            textField.focus()
            return
        }
    }

    // Its called when pressing Next button on the keyboard
    // See textFieldShouldReturn
    func updateNextTag() {
        // There is no next field so set activeFieldTag to nil
        if tag + 1 == totalFields {
            activeFieldTag = nil
        } else {
            // Set next field tag as active
            activeFieldTag = tag + 1
        }
    }

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

    class Coordinator: NSObject, UITextFieldDelegate {

        var parent: CustomTextField

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

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

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

            // Give focus to next field
            parent.updateNextTag()
            parent.text = textField.text ?? ""

            // If there is no next active field then dismiss the keyboard
            if parent.activeFieldTag == nil {
                DispatchQueue.main.async {
                    textField.removeFocus()
                }
            } 

            return true
        }

        func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            DispatchQueue.main.async {
                // To enable user to click on any textField while another is active
                self.parent.activeFieldTag = self.parent.tag
                self.parent.onEditingChanged(true)
            }
            return true
        }

        func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
            self.parent.text = textField.text ?? ""
            DispatchQueue.main.async {
                self.parent.onEditingChanged(false)
            }
            return true
        }

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            if let text = textField.text, let rangeExp = Range(range, in: text) {
                self.parent.text = text.replacingCharacters(in: rangeExp, with: string)
            }
            return true
        }
    }
}

【讨论】:

  • 为什么我收到错误消息说Type 'UIColor' has no member 'pureWhite' 并且“UITextField”类型的值没有成员“焦点”?有什么变化
【解决方案4】:

获取键盘上的go 按钮。尝试将键盘类型更改为 .webSearch。

// 在 Xcode 12 beta 2 和 iOS 14 上测试

.keyboardType(.webSearch)

【讨论】:

  • 很好的答案。对于记录在here 中的不同用例,还有其他很好的选择,例如。 .keyboardType(.twitter).keyboardType(.phonePad)
【解决方案5】:

iOS 15.0+

macOS 12.0+, Mac 催化剂 15.0+, tvOS 15.0+, watchOS 8.0+

submitLabel(_:)

为此视图设置提交标签。

https://developer.apple.com

Form {
    TextField("Username", $viewModel.username)
        .submitLabel(.done)
}

【讨论】:

    猜你喜欢
    • 2011-06-09
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多