Swift学习iOS进阶之路

iOS开发实战 - 准确限制UITextView的输入字数

2019-12-19  本文已影响0人  ArchLL

系统版本:iOS 8.0+
语言版本:swift 5.0
输入模式:简体中文、繁体中文、English(US)
字符支持:暂不支持emoji等特殊字符的字数的准确限制
知识延展UITextField也可以在相关代理方法中用下面的做法限制输入字数

/// 是否需要将textView的光标定位到尾部
private var isLocationToEnd: Bool = false

// MARK:- UITextViewDelegate

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    if text == "" { // 删除字数
        return true
    }
        
    let inputMode = UITextInputMode.activeInputModes.first?.primaryLanguage
    if inputMode == "zh-Hans" || inputMode == "zh-Hant" { // 简体/繁体中文输入法(拼音、手写输入等)
        if let selectedRange = textView.markedTextRange,
            let _ = textView.position(from: selectedRange.start, offset: 0) { // 如果有高亮的文本,如拼音、手写
            // 拼音输入:联想的过程中,location时刻变化(高亮文本的尾部位置),length始终为0
            // 手写输入:联想的过程中不会回调该代理方法,确认联想词后才会进入该代理方法
            if range.length > 0 { // 选中联想词后,location变回高亮文本的起始位置,length为高亮文本的长度,需要对字数限制字数
                return !limitMaxWordsCount(textView, replacementText: text, isLocationToEnd: false)
            }
        } else { // 没有高亮选择的字,对已输入的文字进行字数限制
            if range.location >= maxWordsCount {
                SVProgressHUD.showError(withStatus: "最多可输入\(maxWordsCount)字")
                return false
            } else { // 处理粘贴引起的字数超限, 截取文本后需要自己去移动光标到尾部
                return !limitMaxWordsCount(textView, replacementText: text, isLocationToEnd: true)
            }
        }
    } else { // 中文输入法以外的输入法直接进行字数限制
        if range.location >= maxWordsCount {
            SVProgressHUD.showError(withStatus: "最多可输入\(maxWordsCount)字")
            return false
        } else { // 处理粘贴引起的字数超限, 截取文本后需要自己去移动光标到尾部
            return !limitMaxWordsCount(textView, replacementText: text, isLocationToEnd: true)
        }
    }
        
    return true
}
    
func textViewDidChangeSelection(_ textView: UITextView) {
    if let text = textView.text, isLocationToEnd, text.utf16.count >= maxWordsCount {
        textView.selectedRange = NSRange(location: maxWordsCount, length: 0)
        isLocationToEnd = false
        SVProgressHUD.showError(withStatus: "最多可输入\(maxWordsCount)字")
    }
}
    
func limitMaxWordsCount(_ textView: UITextView, replacementText text: String, isLocationToEnd: Bool) -> Bool {
    let string = textView.text + text
    if string.utf16.count > maxWordsCount {
        textView.text = String(string.prefix(maxWordsCount))
        self.isLocationToEnd = isLocationToEnd
        return true
    }
    return false
}

参考

上一篇 下一篇

猜你喜欢

热点阅读