需求:在文本框中限制输入表情,长度限制
实现原理: 通过这两个控件的代理与通知实现
阅读前提:
- 由于搜狗等不断改善,可能小部分表情未能限制
- 原理较为简单,不再讲解
长度限制,表情限制](https://github.com/XiaoDongXie1024/XDXTextContentHandler)
简书地址 : iOS TextFiled,TextView 长度限制,表情限制
博客地址 : iOS TextFiled,TextView 长度限制,表情限制
掘金地址 : iOS TextFiled,TextView 长度限制,表情限制
注意
- 可以根据需求自行更改提示样式等等
- 可以根据需求自行优化过滤算法
- 好处:我们只需要有这样一个类,以后项目中所有需要限制的地方仅仅需要直接导入头文件,引用类方法即可
使用方法:
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<len;i++)
{
if(!([other rangeOfString:string].location != NSNotFound))
return NO;
}
return YES;
}
/**
* 判断字符串中是否存在emoji
* @param string 字符串
* @return YES(含有表情)
*/
- (BOOL)hasEmoji:(NSString*)string {
NSString *pattern = @"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
BOOL isMatch = [pred evaluateWithObject:string];
return isMatch;
}
/**
判断是不是九宫格
@param string 输入的字符
@return YES(是九宫格拼音键盘)
*/
+ (BOOL)isNineKeyBoard:(NSString *)string {
NSString *other = @"➋➌➍➎➏➐➑➒";
int len = (int)string.length;
for(int i=0;i<len;i++)
{
if(!([other rangeOfString:string].location != NSNotFound))
return NO;
}
return YES;
}
/**
* 判断字符串中是否存在emoji
* @param string 字符串
* @return YES(含有表情)
*/
+ (BOOL)hasEmoji:(NSString*)string {
NSString *pattern = @"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]";
NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
BOOL isMatch = [pred evaluateWithObject:string];
return isMatch;
}
/**
* 判断字符串中是否存在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;
}
+ (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
网友评论