iOS开发中,经常会用到UITextView,UITextField输入文本操作,默认的键盘输入会有emoji表情、空格、非法字符等,会与实际的产品需求不符,这时候就需要我们做限制,禁止输入表情或者空格,甚至标点符号,限制输入的字符个数,小数点之后保留几位,键盘防遮挡(监控键盘高度)等等不同的需求。针对这些需求,博主整理了一下,主要有以下三个方面。
1.屏蔽emoji表情,屏蔽空格
首先说的是屏蔽emoji表情,屏蔽空格,这里主要针对第三方键盘(例如搜狗输入法)和系统键盘的处理。(UITextFieldDelegate和NSNotificationCenter要同时使用)
1)iOS系统键盘使用UITextField的代理即可监控。
#pragma mark - UITextField代理
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
UITextInputMode *inputMode = [UITextInputMode currentInputMode];//会有警告(7.0),可参考替换 UITextInputMode *inputMode = textField.textInputMode
NSString *indentifier = [inputMode performSelector:NSSelectorFromString(@"identifier")];
//会有警告(leak),可被忽略。
if ([indentifier isEqualToString:@"com.sogou.sogouinput.basekeyboard"]) {//搜狗键盘
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:string];
if (isEmoj) {
string = [self disable_emoji:string];
}
else
{
//非emoji
}
//过滤空格
NSString *lTmp = [NSString stringWithFormat:@"%s"," "];
string = [string stringByReplacingOccurrencesOfString:lTmp withString:@""];
}
else
{
if ([indentifier isEqualToString:@"zh_Hans-Pinyin@sw=Pinyin10-Simplified;hw=US"]) {//简体拼音(九宫格)
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:string];
if (isEmoj) {
string = [self disable_emoji:string];
}
else
{
//非emoji
}
//过滤空格
if ([string isEqualToString:@" "]) {
return NO;
}
}
if ([indentifier isEqualToString:@"zh_Hans-Pinyin@sw=Pinyin-Simplified;hw=US"]) {//简体拼音(全键盘)
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:string];
if (isEmoj) {
string = [self disable_emoji:string];
}
else
{
//非emoji
}
//过滤空格
if ([string isEqualToString:@" "]) {
return NO;
}
}
if ([indentifier isEqualToString:@"emoji@sw=Emoji"]) {//表情符号
return NO;
}
if ([indentifier isEqualToString:@"en_US@hw=US;sw=QWERTY"]) {//English(US)
}
//其他键盘同理可自行判断(三方自定义键盘样式、输入模式不确定)
}
return YES;
}
2)针对搜狗输入法,联想文字不受控制,UITextField的代理方法就会监控失效,那么此时我们就不能使用代理了。
#pragma mark - 添加监控
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(textFiledEditChanged:)
name:@"UITextFieldTextDidChangeNotification"
object:textField];//按照自己的需求添加监控对象。
#pragma mark - 监控处理
-(void)textFiledEditChanged:(NSNotification*)obj{
//textFiled
UITextField *textField = (UITextField *)obj.object;
NSString *toBeString = textField.text;
UITextInputMode *inputMode = [UITextInputMode currentInputMode];
//键盘类型
NSString *indentifier = [inputMode performSelector:NSSelectorFromString(@"identifier")];
if ([indentifier isEqualToString:@"com.sogou.sogouinput.basekeyboard"]) {//搜狗键盘
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:toBeString];
if (isEmoj) {
toBeString = [self disable_emoji:toBeString];
}
else
{
//非emoji
}
//过滤空格
NSString *lTmp = [NSString stringWithFormat:@"%s"," "];
toBeString = [toBeString stringByReplacingOccurrencesOfString:lTmp withString:@""];
textField.text = toBeString;
}
else
{
if ([indentifier isEqualToString:@"zh_Hans-Pinyin@sw=Pinyin10-Simplified;hw=US"]) {//简体拼音(九宫格)
}
if ([indentifier isEqualToString:@"zh_Hans-Pinyin@sw=Pinyin-Simplified;hw=US"]) {//简体拼音(全键盘)
}
if ([indentifier isEqualToString:@"emoji@sw=Emoji"]) {//表情符号
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:toBeString];
if (isEmoj) {
toBeString = [self disable_emoji:toBeString];
}
else
{
//非emoji
}
//过滤空格
NSString *lTmp = [NSString stringWithFormat:@"%s"," "];
toBeString = [toBeString stringByReplacingOccurrencesOfString:lTmp withString:@""];
textField.text = toBeString;
}
if ([indentifier isEqualToString:@"en_US@hw=US;sw=QWERTY"]) {//English(US)
//过滤emoji表情
BOOL isEmoj = [self stringContainsEmoji:toBeString];
if (isEmoj) {
toBeString = [self disable_emoji:toBeString];
}
else
{
//非emoji
}
//过滤空格
NSString *lTmp = [NSString stringWithFormat:@"%s"," "];
toBeString = [toBeString stringByReplacingOccurrencesOfString:lTmp withString:@""];
textField.text = toBeString;
}
}
//其他键盘同理可自行判断(三方自定义键盘样式、输入模式不确定)
}
补充说明一下如何屏蔽标点符号
#pragma mark - 屏蔽标点符号(这个算是额外补充,可视情况添加在需要的地方)
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@"@/:;()¥「」"、[]{}#%-*+=_\\|~<>$€^•'@#$%^&*()_+'\""];
toBeString = [toBeString stringByTrimmingCharactersInSet:set];//toBeString为你想要处理的字符串
3) 判断字符串中年是否含有emoji
#pragma mark - 判断NSString字符串是否包含emoji表情
- (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) {
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;
}
4) 过滤表情
#pragma mark - 过滤表情
- (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;
}
2.限制键盘输入的字符个数(小数点后保留n位)
#pragma mark - 宏定义
#define myDotNumbers @"0123456789.\n"
#define myNumbers @"0123456789\n"
#pragma mark - UITextField代理
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string isEqualToString:@"\n"]||[string isEqualToString:@""]) {//按下return
return YES;
}
NSCharacterSet *cs;
NSUInteger nDotLoc = [textField.text rangeOfString:@"."].location;
if (NSNotFound == nDotLoc && 0 != range.location) {
cs = [[NSCharacterSet characterSetWithCharactersInString:myNumbers]invertedSet];
if ([string isEqualToString:@"."]) {
return YES;
}
if (textField.text.length>=20) { //小数点前面20位
return NO;
}
}
else {
cs = [[NSCharacterSet characterSetWithCharactersInString:myDotNumbers]invertedSet];
if (textField.text.length>=23) {//整个最长23位
return NO;
}
}
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
BOOL basicTest = [string isEqualToString:filtered];
if (!basicTest) {
return NO;
}
if (NSNotFound != nDotLoc && range.location > nDotLoc +2) {//小数点后面两位
return NO;
}
return YES;
}
//具体是如何计算的呢?小数点一位,小数点之后两位,小数点之前最长20,整个最长1+2+20=23.
3.监控键盘高度
第三方:IQKeyboard同样的原理,可以参考一下。获取高度,位移单个控件或者view。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
例如iPhone6以上的只使用上面的就可以,但是像iPhone5、iPhone5s这样的需要额外监控。以下是补充说明。
//-----------2016年10月25日更新---------------
#ifdef __IPHONE_5_0
float version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (version >= 5.0) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow1:) name:UIKeyboardWillChangeFrameNotification object:nil];
}
#endif
- (void)keyboardWillShow:(NSNotification *)notification
{
CGRect keyboardRect = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardHeight = keyboardRect.size.height;
}
IQKeyboard的keyboardWillShow:方法。
#pragma mark - UIKeyboad Notification methods
/* UIKeyboardWillShowNotification. */
-(void)keyboardWillShow:(NSNotification*)aNotification
{
_kbShowNotification = aNotification;
if ([self privateIsEnabled] == NO) return;
_IQShowLog([NSString stringWithFormat:@"****** %@ started ******",NSStringFromSelector(_cmd)]);
//Due to orientation callback we need to resave it's original frame. // (Bug ID: #46)
//Added _isTextFieldViewFrameChanged check. Saving textFieldView current frame to use it with canAdjustTextView if textViewFrame has already not been changed. (Bug ID: #92)
if (_isTextFieldViewFrameChanged == NO && _textFieldView)
{
_textFieldViewIntialFrame = _textFieldView.frame;
_IQShowLog([NSString stringWithFormat:@"Saving %@ Initial frame :%@",[_textFieldView _IQDescription],NSStringFromCGRect(_textFieldViewIntialFrame)]);
}
if (CGRectEqualToRect(_topViewBeginRect, CGRectZero)) // (Bug ID: #5)
{
// keyboard is not showing(At the beginning only). We should save rootViewRect.
_rootViewController = [_textFieldView topMostController];
if (_rootViewController == nil) _rootViewController = [[self keyWindow] topMostController];
_topViewBeginRect = _rootViewController.view.frame;
_IQShowLog([NSString stringWithFormat:@"Saving %@ beginning Frame: %@",[_rootViewController _IQDescription] ,NSStringFromCGRect(_topViewBeginRect)]);
}
if (_shouldAdoptDefaultKeyboardAnimation)
{
// Getting keyboard animation.
_animationCurve = [[aNotification userInfo][UIKeyboardAnimationCurveUserInfoKey] integerValue];
_animationCurve = _animationCurve<<16;
}
else
{
_animationCurve = UIViewAnimationOptionCurveEaseOut;
}
// Getting keyboard animation duration
CGFloat duration = [[aNotification userInfo][UIKeyboardAnimationDurationUserInfoKey] floatValue];
//Saving animation duration
if (duration != 0.0) _animationDuration = duration;
CGSize oldKBSize = _kbSize;
// Getting UIKeyboardSize.
CGRect kbFrame = [[aNotification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect screenSize = [[UIScreen mainScreen] bounds];
//Calculating actual keyboard displayed size, keyboard frame may be different when hardware keyboard is attached (Bug ID: #469) (Bug ID: #381)
CGRect intersectRect = CGRectIntersection(kbFrame, screenSize);
if (CGRectIsNull(intersectRect))
{
_kbSize = CGSizeMake(screenSize.size.width, 0);
}
else
{
_kbSize = intersectRect.size;
}
//If last restored keyboard size is different(any orientation accure), then refresh. otherwise not.
if (!CGSizeEqualToSize(_kbSize, oldKBSize))
{
//If _textFieldView is inside UIAlertView then do nothing. (Bug ID: #37, #74, #76)
//See notes:- https://developer.apple.com/Library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html. If it is UIAlertView textField then do not affect anything (Bug ID: #70).
if (_textFieldView != nil && [_textFieldView isAlertViewTextField] == NO)
{
[self adjustFrame];
}
}
_IQShowLog([NSString stringWithFormat:@"****** %@ ended ******",NSStringFromSelector(_cmd)]);
}