iOS - 监控键盘高度、屏蔽字符、限制字符个数

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)]);
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值