有个常用需求是这样:例如修改昵称时,要求输入不超过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)
}
}