禁用Swift UIAlertController按钮,直到输入通过验证

时间:2018-09-28 05:50:27

标签: swift uialertcontroller

我有一个带有导航按钮的表格视图,当按下该按钮时,它会通过警报控制器提示用户输入类别,然后将其插入表格中。我不希望用户提交空字符串或已经存在的类别。这是我到目前为止的代码:

   @objc func promptForCategory() {
    let ac = UIAlertController(title: "Enter a category", message: nil, preferredStyle: .alert)
    ac.addTextField()

    let submitCategory = UIAlertAction(title: "Enter", style: .default) { [unowned self, ac] (action: UIAlertAction) in
        let answer = ac.textFields![0]
        self.enter(answer: answer.text!)
    }

    ac.addAction(submitCategory)
    ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    present(ac, animated: true)
}

func enter(answer: String) {
    if isBlank(answer: answer) {
        if doesContain(answer: answer) {
            categories.append(answer)
            let indexPath = IndexPath(row: 0, section: 0)
            tableView.insertRows(at: [indexPath], with: .automatic)

        }
    }
}

func isBlank(answer: String) -> Bool {
    return answer != ""
}

func doesContain(answer: String) -> Bool {
    let uppercased = categories.map {$0.uppercased()}
    return !uppercased.contains(answer)
}

有没有办法禁用“输入”按钮,直到它通过验证测试?

2 个答案:

答案 0 :(得分:0)

使用此警报使用验证规则TextValidationRule.nonEmpty

import UIKit

/// A validation rule for text input.
public enum TextValidationRule {
    /// Any input is valid, including an empty string.
    case noRestriction
    /// The input must not be empty.
    case nonEmpty
    /// The enitre input must match a regular expression. A matching substring is not enough.
    case regularExpression(NSRegularExpression)
    /// The input is valid if the predicate function returns `true`.
    case predicate((String) -> Bool)


    public func isValid(_ input: String) -> Bool {
        switch self {
        case .noRestriction:
            return true
        case .nonEmpty:
            return !input.isEmpty
        case .regularExpression(let regex):
            let fullNSRange = NSRange(input.startIndex..., in: input)
            return regex.rangeOfFirstMatch(in: input, options: .anchored, range: fullNSRange) == fullNSRange
        case .predicate(let p):
            return p(input)
        }
    }

}


extension UIAlertController {

    public enum TextInputResult {
        /// The user tapped Cancel.
        case cancel
        /// The user tapped the OK button. The payload is the text they entered in the text field.
        case ok(String)
    }


    /// Creates a fully configured alert controller with one text field for text input, a Cancel and
    /// and an OK button.
    ///
    /// - Parameters:
    ///   - title: The title of the alert view.
    ///   - message: The message of the alert view.
    ///   - cancelButtonTitle: The title of the Cancel button.
    ///   - okButtonTitle: The title of the OK button.
    ///   - validationRule: The OK button will be disabled as long as the entered text doesn't pass
    ///     the validation. The default value is `.noRestriction` (any input is valid, including
    ///     an empty string).
    ///   - textFieldConfiguration: Use this to configure the text field (e.g. set placeholder text).
    ///   - onCompletion: Called when the user closes the alert view. The argument tells you whether
    ///     the user tapped the Close or the OK button (in which case this delivers the entered text).
    public convenience init(title: String, message: String? = nil,
                            cancelButtonTitle: String, okButtonTitle: String,
                            validate validationRule: TextValidationRule = .noRestriction,
                            textFieldConfiguration: ((UITextField) -> Void)? = nil,
                            onCompletion: @escaping (TextInputResult) -> Void) {
        self.init(title: title, message: message, preferredStyle: .alert)

        /// Observes a UITextField for various events and reports them via callbacks.
        /// Sets itself as the text field's delegate and target-action target.
        class TextFieldObserver: NSObject, UITextFieldDelegate {

            let textFieldValueChanged: (UITextField) -> Void
            let textFieldShouldReturn: (UITextField) -> Bool

            init(textField: UITextField, valueChange: @escaping (UITextField) -> Void, shouldReturn: @escaping (UITextField) -> Bool) {

                textFieldValueChanged = valueChange
                textFieldShouldReturn = shouldReturn
                super.init()
                textField.delegate = self
                textField.addTarget(self, action: #selector(TextFieldObserver.textFieldValueChanged(sender:)), for: .editingChanged)
            }

            @objc func textFieldValueChanged(sender: UITextField) {
                textFieldValueChanged(sender)
            }
            func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                return textFieldShouldReturn(textField)
            }
        }


        var textFieldObserver: TextFieldObserver?

         // Every `UIAlertAction` handler must eventually call this
        func finish(result: TextInputResult) {
            // Capture the observer to keep it alive while the alert is on screen
            textFieldObserver = nil
            onCompletion(result)
        }

        let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .cancel, handler: { _ in
            finish(result: .cancel)
        })
        let okAction = UIAlertAction(title: okButtonTitle, style: .default, handler: { [unowned self] _ in
            finish(result: .ok(self.textFields?.first?.text ?? ""))
        })

        addAction(cancelAction)
        addAction(okAction)

        preferredAction = okAction

        addTextField { textField in
            textFieldConfiguration?(textField)
            textFieldObserver = TextFieldObserver(textField: textField, valueChange: { textField in
                okAction.isEnabled = validationRule.isValid(textField.text ?? "")
            }, shouldReturn: { textField -> Bool in
               return validationRule.isValid(textField.text ?? "")
            })
        }

        // Start with a disabled OK button if necessary
        okAction.isEnabled = validationRule.isValid(textFields?.first?.text ?? "")
    }

}

//视图控制器中的示例用法

 let alert = UIAlertController(title: "Alert", cancelButtonTitle: "Cancel", okButtonTitle: "Ok", validate: TextValidationRule.nonEmpty) { _ in

        }
        present(alert, animated: true, completion: nil)

答案 1 :(得分:0)

您可以通过使用

来禁用/启用UIAlertAction
alertAction.isEnabled = false (or) true

在您的代码中

submitCategory.isEnabled = false

ac.actions.first?.isEnabled = false