UITextField 限制输入字数解决方案

2015-09-10, Thu | Comments

本文提供了集中限制UITextField输入字数的方式,并针对中文联想词提供了解决方案。所用代码为Swift。

方法一:利用delegate实现

UITextFieldDelegate 提供了函数可以判断用户输入过程,demo如下

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    // 不检测“删除”键
    if count(string) == 0 {
        return true
    }

    // 防止UITextField ‘Undo’引发crash
    if range.location + range.length > count(textField.text){
        return false
    }

    let newLength = count(textField.text) + count(string) - range.length
    return newLength <= limitation - 1
}

在TextField 更改之前,会通过该函数询问delegate是否应该改变text内容,因此我们可以在这个函数中约定是否接收用户的输入。 但是这种方式针对中文输入法有个缺陷,它无法检测和限制联想词的输入。因此该方式不适合中文输入法下的字数限制

方法二:监控 UIControlEvents.EditingChanged 或者 UITextFieldTextDidChangeNotification

UITextField的text内容再更改的时候,会触发UIControlEvents.EditingChanged 并发送 UITextFieldTextDidChangeNotification。因此可以通过监听事件或者接收通知的方式来获知text内容的改变,在改变的时候添加限制条件。demo如下:

增加监听事件

_textField.addTarget(self, action: Selector("textFieldDidChanged:"), forControlEvents: UIControlEvents.EditingChanged)

限制字数

func textFieldDidChanged(textField: UITextField) {
    if limitation > 0 {
        // markedTextRange指的是当前高亮选中的,除了长按选中,用户中文输入拼音过程往往也是高亮选中状态
        if let selectedRange = textField.markedTextRange {

        } else {
            let text = textField.text
            if text.length > limitation {
                let range = Range(start: text.startIndex, end: advance(text.startIndex, limitation))
                let subText = text.substringWithRange(range)
                textField.text = subText
            }
        }
    }

}

通过这种方式对字数进行限制,产生的效果是用户在中文拼音输入状态不会限制字数,而是在用户确认输入的瞬间进行字数限制截取。目前跟Android自身带的字数限制功能效果一致

方法三:delegate与监控方式相结合

利用方法二已经可以满足UITextField字数限制的需求。但是如果想在用户输入拼音阶段就进行字数限制,防止用户输入过长,那么建议结合delegate。因为delegate在用户输入过程就可以判断输入的长度,从而判断是否允许用户继续输入;而在输入确认的时刻,再利用监控方式,防止中文联想词的输入。demo如下:

增加监控

_textField.addTarget(self, action: Selector("textFieldDidChanged:"), forControlEvents: UIControlEvents.EditingChanged)

限制字数

func textFieldDidChanged(textField: UITextField) {
    if limitation > 0 {
        // markedTextRange指的是当前高亮选中的,除了长按选中,用户中文输入拼音过程往往也是高亮选中状态
        if let selectedRange = textField.markedTextRange {

        } else {
            let text = textField.text
            if text.length > limitation {
                let range = Range(start: text.startIndex, end: advance(text.startIndex, limitation))
                let subText = text.substringWithRange(range)
                textField.text = subText
            }
        }
    }

}

delegate监控用户输入

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    // 不检测“删除”键
    if count(string) == 0 {
        return true
    }

    // 防止UITextField ‘Undo’引发crash
    if range.location + range.length > count(textField.text){
        return false
    }

    let newLength = count(textField.text) + count(string) - range.length
    return newLength <= limitation - 1
}       

从上面大家可以看出,监控也可在用户输入过程进行字数限制,但是效果不好。因为 textField.text = subText,用户输入一旦过长,文本框内容立马会被用户输入所替代,但这个时候往往输入的是几个拼音字母,因此用户体验不好。而delegate方法不会立马替换文本框内容,而是限制了用户输入,用户体验比较好。也因为这个原因,我们在delegate上的检测limitation要留有余量。

Comments