需求:在文字框中限制輸入表情,長度限制
實現原理: 通過這兩個控制元件的代理與通知實現
閱讀前提:
- 由於搜狗等不斷改善,可能小部分表情未能限制
- 原理較為簡單,不再講解
注意
- 可以根據需求自行更改提示樣式等等
- 可以根據需求自行優化過濾演算法
- 好處:我們只需要有這樣一個類,以後專案中所有需要限制的地方僅僅需要直接匯入標頭檔案,引用類方法即可
使用方法:
1. 匯入標頭檔案
複製程式碼
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];
}
- (void)textFiledEditChanged:(NSNotification *)obj {
[XDXTextContentHandler handleTextFiledEditChangedWithNotification:obj textMaxLength:kTitleTextMaxLength isShowTip:YES];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
return [XDXTextContentHandler handleTextFiledShouldChangeTextInRangeWithTextFiled:textField range:range replacementText:string isShowTip:YES];
}
- (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
+ (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;
}
// 字母、數字、中文常用字元正則判斷(不包括空格)
+ (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
複製程式碼