Swift中文輸入法限制字數以及常用字符串處理方法

有個常用需求是這樣:例如修改暱稱時,要求輸入不超過10個字符。(中英文數字都算一個字符)。如果用textField自帶的textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool 這個代理方法的話,會有一個問題是這樣。當使用中文輸入法的時候,在輸入拼音的時候,還沒有選中漢字,你輸入的拼音字母已經被統計在內了。這樣就不符合需求。

上面的問題不論是OC還是Swift,解決思路是一樣的。之前的項目裏我直接把OC的內容翻譯到Swift裏面,發現直接翻譯過來的會存在一些問題。下面我在代碼裏具體寫一下解決思路以及遇到的問題的解決辦法:


///首先註冊通知
private func addNoti() {
        NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChange(noti:)), name: NSNotification.Name.UITextFieldTextDidChange, object: myTextFeild)
    }

    @objc func textFieldDidChange(noti: Notification) {
        if let field = noti.object as? UITextField {
            if let toBeString = field.text {
                ///鍵盤輸入模式(OC裏面通過[[UITextInputMode currentInputMode] primaryLanguage]來獲取當前輸入法,Swift裏面沒有currentInputMode這個東西,只能是獲取你正在使用的所有輸入法,然後第一個就是當前輸入法)
                if let language = UITextInputMode.activeInputModes.first?.primaryLanguage {
                    if language == "zh-Hans" {///中文輸入法
                        ///這裏跟OC也有點區別,直接如下這麼寫就行,只有在輸入拼音選中後纔會走到else裏面,然後在else裏面寫條件判斷就好了
                        if let _ = field.markedTextRange {
                        }else {
                            if toBeString.length > 10 {
                                ///swift裏面處理字符串特別麻煩,這裏非要用String.index 這種類型,然後我給string常用的一些方法都封裝了一下。這裏直接這麼調用就可以
                                field.text = toBeString.substring(to: 10)
                            }
                        }
                    }else {///非中文輸入法,直接統計字數和限制,這裏沒有考慮其他語種的情況
                        if toBeString.length > 10 {
                            field.text = toBeString.substring(to: 10)
                        }
                    }
                }
            }
        }
    }

extension String {

    //MARK:-截取字符串從開始到 index
    func substring(to index: Int) -> String {
        guard let end_Index = validEndIndex(original: index) else {
            return self;
        }

        return String(self[startIndex..<end_Index]);
    }
    //MARK:-截取字符串從index到結束
    func substring(from index: Int) -> String {
        guard let start_index = validStartIndex(original: index)  else {
            return self
        }
        return String(self[start_index..<endIndex])
    }
    //MARK:-切割字符串(區間範圍 前閉後開)
    func sliceString(_ range:CountableRange<Int>)->String{

        guard
            let startIndex = validStartIndex(original: range.lowerBound),
            let endIndex   = validEndIndex(original: range.upperBound),
            startIndex <= endIndex
            else {
                return ""
        }

        return String(self[startIndex..<endIndex])
    }
    //MARK:-切割字符串(區間範圍 前閉後閉)
    func sliceString(_ range:CountableClosedRange<Int>)->String{

        guard
            let start_Index = validStartIndex(original: range.lowerBound),
            let end_Index   = validEndIndex(original: range.upperBound),
            startIndex <= endIndex
            else {
                return ""
        }
        if(endIndex.encodedOffset <= end_Index.encodedOffset){
            return String(self[start_Index..<endIndex])
        }
        return String(self[start_Index...end_Index])

    }
    //MARK:-校驗字符串位置 是否合理,並返回String.Index
    private func validIndex(original: Int) -> String.Index {

        switch original {
        case ...startIndex.encodedOffset : return startIndex
        case endIndex.encodedOffset...   : return endIndex
        default                          : return index(startIndex, offsetBy: original)
        }
    }
    //MARK:-校驗是否是合法的起始位置
    private func validStartIndex(original: Int) -> String.Index? {
        guard original <= endIndex.encodedOffset else { return nil }
        return validIndex(original:original)
    }
    //MARK:-校驗是否是合法的結束位置
    private func validEndIndex(original: Int) -> String.Index? {
        guard original >= startIndex.encodedOffset else { return nil }
        return validIndex(original:original)
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章