在平常項目開發中,咱們常常用到UITextView UITextField這兩個控件,今天咱們來說講如何方便簡單的限制這兩個控件的輸入字數以及精準顯示剩餘字數。git
以前在項目中遇到了UITextView的限制輸入以及剩餘字數顯示,由於項目比較老,也有寫好的限制輸入功能,可是當這兩種功能須要同時實現時,須要在原來的基礎上添加不少重複的代碼,恰好最近也閒下來了,就準備本身動手寫寫。github
首先咱們先拿UITextView來講吧,UITextView主要用於多行文本的輸入,爲了限制它的輸入字數,我使用的方法是自定義一個textView,自定義的textView自身實現UITextViewDelegate方法,子類的屬性有如下幾個:bash
@property (nonatomic, assign) NSInteger tvLimitNumber;//最大輸入字數
@property (nonatomic, assign, getter=isForbidSystemEmoji) BOOL shouldForbidSystemEmoji;//是否禁止系統表情輸入
@property (nonatomic, assign) BOOL returnKeyDone;//return鍵點擊效果是否完成輸入
@property (nonatomic, weak) id<BWTextViewDelegate> tvDelegate;//自定義代理方法
複製代碼
爲了實現限制輸入字數,所用到的主要是如下兩個代理方法:ui
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (void)textViewDidChange:(UITextView *)textView;
複製代碼
第一個代理方法能夠實時的獲取到當前輸入的每個字符,而且控制是否將輸入的字符加入到最後的字符串中,咱們在代理方法中實現如下內容來限制輸入的字符是否加入到最後的字符串中:atom
//最大限制數量小於0 則不作限制數量限制
if (self.tvLimitNumber <= 0) {
return YES;
}
//獲取高亮部分
UITextRange *markedRange = [textView markedTextRange];
UITextPosition *position = [textView positionFromPosition:markedRange.start offset:0];
//若是有高亮且當前字數開始位置小於最大限制時容許輸入
if (markedRange && position) {
NSInteger startOffset = [textView offsetFromPosition:textView.beginningOfDocument toPosition:markedRange.start];
NSInteger endOffset = [textView offsetFromPosition:textView.beginningOfDocument toPosition:markedRange.end];
NSRange offsetRange = NSMakeRange(startOffset, endOffset - startOffset);
if (offsetRange.location < self.tvLimitNumber) {
return YES;
} else {
return NO;
}
}
複製代碼
在第二個代理方法中,咱們須要實現的是判斷textView中的文本是否超過限制字數,若是超出則截取出子串並賦值給textView.text,實現文本的限制:spa
//若限制數量小於等於0 則不對輸入作限制
if (self.tvLimitNumber <= 0) {
//執行自定義代理方法
[self textViewValueDidChanged:textView];
return;
}
NSString *lang = [[[UITextInputMode activeInputModes] firstObject] primaryLanguage];//當前的輸入模式
//獲取高亮部分
UITextRange *range = [textView markedTextRange];
UITextPosition *start = range.start;
UITextPosition*end = range.end;
NSInteger selectLength = [textView offsetFromPosition:start toPosition:end];
//存在高亮則不計算高度
if (range && selectLength) {
return;
}
if ([lang isEqualToString:@"zh-Hans"]) {
NSInteger contentLength = textView.text.length - selectLength;
if (contentLength >= self.tvLimitNumber) {
textView.text = [textView.text substringToIndex:self.tvLimitNumber];
//文字數量超出最大限制數量
}
} else {
if (textView.text.length >= self.tvLimitNumber) {
textView.text = [textView.text substringToIndex:self.tvLimitNumber];
//文字數量超出最大限制數量
}
}
//執行自定義代理方法
[self textViewValueDidChanged:textView];
複製代碼
爲了讓在外部也能實現UITextView的代理方法,自定義的textView添加一個協議,協議的大體內容都是UITextViewDelegate中的內容,這樣就不用擔憂沒法在外部不能自定義一些操做了,自定義的代理方法主要有如下幾種:代理
- (void)bwTextViewDidChanged:(UITextView *)textView;
- (BOOL)bwTextView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
- (BOOL)bwTextViewShouldBeginEditing:(UITextView *)textView;
- (BOOL)bwTextViewShouldEndEditing:(UITextView *)textView;
- (void)bwTextViewDidBeginEditing:(UITextView *)textView;
- (void)bwTextViewDidEndEditing:(UITextView *)textView;
複製代碼
接下來說講UITextField,實現的原理是同樣的,不過UITextFieldDelegate中並無暴露出相似UITextView:- (void)textViewDidChange:(UITextView *)textView這樣的方法,爲了實現相似的功能,我在自定義的UITextField中添加了實時監聽UITextField內容變化的通知,並在通知方法中實現截取子串的操做:code
- (void)setTfLimitNumber:(NSInteger)tfLimitNumber {
_tfLimitNumber = tfLimitNumber;
//添加通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChanged) name:UITextFieldTextDidChangeNotification object:nil];
}
複製代碼
- (void)textFieldDidChanged {
//若限制數量小於等於0 則不對輸入作限制
if (self.tfLimitNumber <= 0) {
//執行自定義代理方法
[self bwTextFieldDidChanged:self];
return;
}
NSString *lang = [[[UITextInputMode activeInputModes] firstObject] primaryLanguage];//當前的輸入模式
//獲取高亮部分
UITextRange *range = [self markedTextRange];
UITextPosition *start = range.start;
UITextPosition*end = range.end;
NSInteger selectLength = [self offsetFromPosition:start toPosition:end];
//存在高亮則不計算高度
if (range && selectLength) {
return;
}
if ([lang isEqualToString:@"zh-Hans"]) {
NSInteger contentLength = self.text.length - selectLength;
if (contentLength >= self.tfLimitNumber) {
self.text = [self.text substringToIndex:self.tfLimitNumber];
//文字數量超出最大限制數量
}
} else {
if (self.text.length >= self.tfLimitNumber) {
self.text = [self.text substringToIndex:self.tfLimitNumber];
//文字數量超出最大限制數量
}
}
//執行自定義代理方法
[self bwTextFieldDidChanged:self];
}
複製代碼
以上就是自定義UITextView UITextField實現限制輸入字數以及精準獲取剩餘字數的功能,實現這類功能只須要初始化時設定須要限制的字數便可,減小了重複實現代理方法的代碼,大大的增長了代碼的美觀以及封裝性。server
代碼請戳這裏開發