需求:在文本框中限制输入表情,长度限制
实现原理: 通过这两个控件的代理与通知实现
阅读前提:
- 由于搜狗等不断改善,可能小部分表情未能限制
- 原理较为简单,不再讲解
Github:
简书地址 :
博客地址 :
掘金地址 :
注意
- 可以根据需求自行更改提示样式等等
- 可以根据需求自行优化过滤算法
- 好处:我们只需要有这样一个类,以后项目中所有需要限制的地方仅仅需要直接导入头文件,引用类方法即可
使用方法:
1. 导入头文件
#import "XDXTextContentHandler.h"复制代码
2. 直接在对应的代理或通知中对用头文件即可
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.testTextFiled.delegate = self; self.testTextView.delegate = self; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFiledEditChanged:) name:@"UITextFieldTextDidChangeNotification" object:self.testTextFiled];}#pragma mark - Notification- (void)textFiledEditChanged:(NSNotification *)obj { [XDXTextContentHandler handleTextFiledEditChangedWithNotification:obj textMaxLength:kTitleTextMaxLength isShowTip:YES];}#pragma mark - Delegate#pragma mark TextFiled- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { return [XDXTextContentHandler handleTextFiledShouldChangeTextInRangeWithTextFiled:textField range:range replacementText:string isShowTip:YES];}#pragma mark TextView- (void)textViewDidChange:(UITextView *)textView { [XDXTextContentHandler handleTextViewDidChangeWithTextView:textView textMaxLength:kTitleTextMaxLength isShowTip:YES];}- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text { return [XDXTextContentHandler handleTextViewShouldChangeTextInRangeWithTextView:textView range:range replacementText:text isShowTip:YES];}复制代码
具体实现:
- 长度限制:即检测到超过设定长度后截取字符串
- 表情限制:检测是苹果自带还是第三方,过滤关键字
@implementation XDXTextContentHandler#pragma mark - Public Main Func+ (void)handleTextFiledEditChangedWithNotification:(NSNotification *)notification textMaxLength:(int)textMaxLength isShowTip:(BOOL)isShowTip { UITextField *textField = (UITextField *)notification.object; if ([textField isFirstResponder]) { NSString *toBeString = textField.text; if (toBeString.length > textMaxLength) { textField.text = [toBeString substringToIndex:textMaxLength]; if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Text max length is %d",textMaxLength]]; } } }}+ (void)handleTextViewDidChangeWithTextView:(UITextView *)textView textMaxLength:(int)textMaxLength isShowTip:(BOOL)isShowTip { if ([textView isFirstResponder]) { if (textView.text.length > textMaxLength) { textView.text = [textView.text substringToIndex:textMaxLength]; if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Text max length is %d",textMaxLength]]; } } } NSString *toBeString = textView.text; if (![self isInputRuleAndBlank:toBeString]) { textView.text = [self disable_emoji:toBeString]; if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Not input emoji"]]; } return; } NSString *lang = [[textView textInputMode] primaryLanguage]; // 获取当前键盘输入模式 NSLog(@"%@",lang); if([lang isEqualToString:@"zh-Hans"]) { //简体中文输入,第三方输入法(搜狗)所有模式下都会显示“zh-Hans” UITextRange *selectedRange = [textView markedTextRange]; //获取高亮部分 UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0]; //没有高亮选择的字,则对已输入的文字进行字数统计和限制 if(!position) { NSString *getStr = [self getSubString:toBeString textMaxLength:textMaxLength]; if(getStr && getStr.length > 0) { textView.text = getStr; } } } else{ NSString *getStr = [self getSubString:toBeString textMaxLength:textMaxLength]; if(getStr && getStr.length > 0) { textView.text= getStr; } }}+ (BOOL)handleTextViewShouldChangeTextInRangeWithTextView:(UITextView *)textView range:(NSRange)range replacementText:(NSString *)text isShowTip:(BOOL)isShowTip { if ([textView isFirstResponder]) { if ([[[textView textInputMode] primaryLanguage] isEqualToString:@"emoji"] || ![[textView textInputMode] primaryLanguage]) { return NO; } //判断键盘是不是九宫格键盘 if ([self isNineKeyBoard:text]){ return YES; }else{ if ([self hasEmoji:text] || [self stringContainsEmoji:text]){ if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Not input emoji"]]; } return NO; } } } return YES;}+ (BOOL)handleTextFiledShouldChangeTextInRangeWithTextFiled:(UITextField *)textFiled range:(NSRange)range replacementText:(NSString *)text isShowTip:(BOOL)isShowTip { if ([textFiled isFirstResponder]) { if ([[[textFiled textInputMode] primaryLanguage] isEqualToString:@"emoji"] || ![[textFiled textInputMode] primaryLanguage]) { if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Not input emoji"]]; } return NO; } //判断键盘是不是九宫格键盘 if ([self isNineKeyBoard:text]){ return YES; }else{ if ([self hasEmoji:text] || [self stringContainsEmoji:text]){ if (isShowTip) { [self showAlertVCWithTitle:@"Warning" message:[NSString stringWithFormat:@"Not input emoji"]]; } return NO; } } } return YES;}#pragma mark - Private#pragma mark TextView禁止表情相关// 字母、数字、中文常用字符正则判断(不包括空格)+ (BOOL)isInputRuleNotBlank:(NSString *)str { NSString *pattern = @"^[a-zA-Z,.!@#$%^:;\\=+-_()¥。“、\u4E00-\u9FA5\\d\\n]*$"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern]; BOOL isMatch = [pred evaluateWithObject:str]; return isMatch;}// 字母、数字、中文正则判断(包括空格)(在系统输入法中文输入时会出现拼音之间有空格,需要忽略,当按return键时会自动用字母替换,按空格输入响应汉字)+ (BOOL)isInputRuleAndBlank:(NSString *)str { NSString *pattern = @"^[a-zA-Z\u4E00-\u9FA5\\d\\s]*$"; NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern]; BOOL isMatch = [pred evaluateWithObject:str]; return isMatch;}// 获得 kIntroTextViewMaxLength长度的字符+ (NSString *)getSubString:(NSString*)string textMaxLength:(int)textMaxLength { NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); NSData *data = [string dataUsingEncoding:encoding]; NSInteger length = [data length]; if (length > textMaxLength) { NSData *data1 = [data subdataWithRange:NSMakeRange(0, textMaxLength)]; NSString *content = [[NSString alloc] initWithData:data1 encoding:encoding];//注意:当截取kIntroTextViewMaxLength长度字符时把中文字符截断返回的content会是nil if (!content || content.length == 0) { data1 = [data subdataWithRange:NSMakeRange(0, textMaxLength - 1)]; content = [[NSString alloc] initWithData:data1 encoding:encoding]; } return content; } return nil;}+ (NSString *)disable_emoji:(NSString *)text { NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]" options:NSRegularExpressionCaseInsensitive error:nil]; NSString *modifiedString = [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""]; return modifiedString;}/** * 判断字符串中是否存在emoji * @param string 字符串 * @return YES(含有表情) */- (BOOL)stringContainsEmoji:(NSString *)string { __block BOOL returnValue = NO; [string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { const unichar hs = [substring characterAtIndex:0]; // surrogate pair if (0xd800 <= hs && hs <= 0xdbff) { if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f77f) { returnValue = YES; } } } else if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; if (ls == 0x20e3) { returnValue = YES; } } else { // non surrogate if (0x2100 <= hs && hs <= 0x27ff) { returnValue = YES; } else if (0x2B05 <= hs && hs <= 0x2b07) { returnValue = YES; } else if (0x2934 <= hs && hs <= 0x2935) { returnValue = YES; } else if (0x3297 <= hs && hs <= 0x3299) { returnValue = YES; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { returnValue = YES; } } }]; return returnValue;}/** 判断是不是九宫格 @param string 输入的字符 @return YES(是九宫格拼音键盘) */-(BOOL)isNineKeyBoard:(NSString *)string { NSString *other = @"➋➌➍➎➏➐➑➒"; int len = (int)string.length; for(int i=0;i 1) { const unichar ls = [substring characterAtIndex:1]; const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f77f) { returnValue = YES; } } } else if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; if (ls == 0x20e3) { returnValue = YES; } } else { // non surrogate if (0x2100 <= hs && hs <= 0x27ff) { returnValue = YES; } else if (0x2B05 <= hs && hs <= 0x2b07) { returnValue = YES; } else if (0x2934 <= hs && hs <= 0x2935) { returnValue = YES; } else if (0x3297 <= hs && hs <= 0x3299) { returnValue = YES; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { returnValue = YES; } } }]; return returnValue;}+ (void)showAlertVCWithTitle:(NSString *)title message:(NSString *)message { UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *OKAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:nil]; [alertVC addAction:OKAction]; UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController; [rootVC presentViewController:alertVC animated:YES completion:nil];}@end复制代码