使用硬件键盘时,不会为UITextField调用shouldChangeText

时间:2017-04-28 12:06:09

标签: ios swift uitextfield

我有一个UITextField的子类,我希望子类控制哪些输入值有效。我通过覆盖子类中的shouldChangeText(in:, replacementText:) -> Bool方法解决了这个问题。但只有在使用屏幕键盘时才会调用此功能。如果我使用硬件键盘,它就不会被调用。

使用硬件键盘时,textField(_ textField:, shouldChangeCharactersIn:, replacementString:) -> Bool会调用UITextFieldDelegate。但我不想将委托分配给文本字段本身,因为我需要某些视图控制器中的委托用于其他目的。所以我需要一种替代方法来验证输入值,例如shouldChangeText(in:, replacementText:) -> Bool为我提供了屏幕键盘。

我可以在委托方法的堆栈跟踪中看到系统已调用[UITextField keyboardInput:shouldInsertText:isMarkedText:],但我无法覆盖它。

有没有办法解决这个问题,而没有指派代表?

1 个答案:

答案 0 :(得分:2)

这是一个替代解决方案,允许您的"真实"文本字段委托和您的自定义文本字段类,以实现一个更多的委托方法。

下面的代码允许此自定义文本字段实现任何所需的UITextField委托方法,同时仍允许真正的委托实现它所需的任何方法。唯一的要求是,对于在自定义文本字段中实现的任何委托方法,您必须检查真实委托是否也实现它并根据需要调用它。在真正的委托类中实现的任何委托方法都应该正常写入。

这个简单的自定义文本字段示例设置为仅允许数字。但它让文本字段的真正代表进行其他验证,例如只允许一定长度的数字或特定范围或其他任何验证。

import UIKit

class MyTextField: UITextField, UITextFieldDelegate {
    private var realDelegate: UITextFieldDelegate?

    // Keep track of the text field's real delegate
    override var delegate: UITextFieldDelegate? {
        get {
            return realDelegate
        }
        set {
            realDelegate = newValue
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)

        // Make the text field its own delegate    
        super.delegate = self
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // Make the text field its own delegate    
        super.delegate = self
    }

    // This is one third of the magic
    override func forwardingTarget(for aSelector: Selector!) -> Any? {
        if let realDelegate = realDelegate, realDelegate.responds(to: aSelector) {
            return realDelegate
        } else {
            return super.forwardingTarget(for: aSelector)
        }
    }

    // This is another third of the magic
    override func responds(to aSelector: Selector!) -> Bool {
        if let realDelegate = realDelegate, realDelegate.responds(to: aSelector) {
            return true
        } else {
            return super.responds(to: aSelector)
        }
    }

    // And the last third
    // This only allows numbers to be typed into the text field.
    // Of course this can be changed to do whatever validation you need in this custom text field
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if string.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) != nil {
            return false // Not a number - fail
        } else {
            // The string is valid, now let the real delegate decide
            if let delegate = realDelegate, delegate.responds(to: #selector(textField(_:shouldChangeCharactersIn:replacementString:))) {
                return delegate.textField!(textField, shouldChangeCharactersIn: range, replacementString: string)
            } else {
                return true
            }
        }
    }
}

我作为练习留下的唯一其他复杂情况是自定义文本字段想要修改更改文本然后允许真实委托确定是否应该允许修改字符串/范围。