有個常用需求是這樣:例如修改暱稱時,要求輸入不超過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)
}
}