• UITextField最大字符数和最大字节数的限制


    UITextView,UITextfield中有很多坑,网上的方法也很多,但是用过之后暂时没有发现一个好用。这里我给大家几组测试用例可以一试,为啥不好用。

    1. 限制10个字节,输入2个Emoj之后是8个字节(一个Emoj是4个字节),此时再输入一个中文,看看结果如何(中文的UTF8占3个字节)
    2. 限制5个字符,一个Emoj是2个字符,其他都是一个。此时输入两个Emoj,再输入中文,然后中文联想试试。

    就目前的情况来说,看了很多资料,并没有一个通用的能限制字符数和字节数的封装。这里全面进行了总结,并进行了封装。欢迎大家下载。

    一. 字符限制

    1. 错误方法

    常见的这种方法是错误的,会导致Emoj表情的截取问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
    if(range.length + range.location > textField.text.length)
    {
    return NO;
    }

    NSUInteger newLength = [textField.text length] + [string length] - range.length;
    return newLength <= 5;
    }

    这种限制方法会导致拼音下出现这种情况,且无法输入.无法输入满5个字符。在emoj表情也有问题

    2. 推荐方法

    使用rangeOfComposedCharacterSequencesForRange, 防止在range范围内整词被截断.因为中文的UTF8是3字节,Emoj是4个字节,且不能边输入边限制,否则中文联想的时候就无法继续输入。只能输入后在textfieldchange的时候进行截断。
    综上所述,思路如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    - (void)textFieldDidChange:(UITextField *)textField
    {
    NSString *text = textField.text;
    // NSLog(@"text:%@",text);

    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];

    // 没有高亮选择的字,则对已输入的文字进行字数统计和限制,防止中文被截断

    if (!position){
    //---字符处理
    if (text.length > _maxLength){
    //中文和emoj表情存在问题,需要对此进行处理
    NSRange range;
    NSUInteger inputLength = 0;
    for(int i=0; i < text.length && inputLength <= _maxLength; i += range.length) {
    range = [textField.text rangeOfComposedCharacterSequenceAtIndex:i];
    inputLength += [text substringWithRange:range].length;
    if (inputLength > _maxLength) {
    NSString* newText = [text substringWithRange:NSMakeRange(0, range.location)];
    textField.text = newText;
    }
    }
    }
    }
    }

    二. 字节限制

    1. 限制字节数

    在UTF8中,英文和数字是1个字节,汉子是3个字节,emoji是3或者4个字节。这里的难度比上面更大,如果截取失败,极有可能出现乱码。这里我们的做法如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    - (void)textFieldDidChange:(UITextField *)textField
    {
    NSString *text = textField.text;
    // NSLog(@"text:%@",text);

    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];

    // 没有高亮选择的字,则对已输入的文字进行字数统计和限制,防止中文被截断

    if (!position){
    //---字节处理
    //Limit
    NSUInteger textBytesLength = [textField.text lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    if (textBytesLength > _maxBytesLength) {
    NSRange range;
    NSUInteger byteLength = 0;
    for(int i=0; i < text.length && byteLength <= _maxBytesLength; i += range.length) {
    range = [textField.text rangeOfComposedCharacterSequenceAtIndex:i];
    byteLength += strlen([[text substringWithRange:range] UTF8String]);
    if (byteLength > _maxBytesLength) {
    NSString* newText = [text substringWithRange:NSMakeRange(0, range.location)];
    textField.text = newText;
    }
    }
    }
    }
    if (self.textFieldChange) {
    self.textFieldChange(self,textField.text);
    }
    }

    三. 放弃键盘

    1. 能拿到uitextfield的时候用

    1
    2
    3
    4
    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    return [textField resignFirstResponder];
    }

    2. 点击view消失的时候用

    1
    [self.view endEditing:YES];

    3. 难以获取的时候用

    1
    [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];

    或者

    1
    [[[UIApplication sharedApplication] keyWindow] endEditing:YES];

    2.Tableview点击空白处或者滚动时消失

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(fingerTapped:)];
    [self.view addGestureRecognizer:singleTap];
    }

    #pragma mark- 键盘消失
    -(void)fingerTapped:(UITapGestureRecognizer *)gestureRecognizer{
    [self.view endEditing:YES];
    }
    -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    [self.view endEditing:YES];
    }

    四. 正则表达式限制

    请参考正则表达式语法表,这里我提供了两种表达式给大家参考,一个Int,一个无unsignedInt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    -(BOOL) isTextFieldMatchWithRegularExpression:(NSString *)exporession{

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",exporession];
    return [predicate evaluateWithObject:self];
    }
    -(BOOL) isTextFieldIntValue{
    return [self isTextFieldMatchWithRegularExpression:@"[-]{0,1}[0-9]*"];
    }
    -(BOOL) isTextFieldUnsignedIntValue{
    return [self isTextFieldMatchWithRegularExpression:@"[0-9]+"];
    }

    五. UITextfield的键盘事件多次回调问题

    1.键盘高度遮挡问题

    一般出现遮挡的时候我们用以下代码,看看当前textfield是否在键盘下面,在的话算出键盘的顶端和textfield的底部的距离,然后做偏移动画

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    - (void)keyboardWillShow:(NSNotification *)notification {

    NSDictionary *userInfo = [notification userInfo];

    NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardRect = [aValue CGRectValue];
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

    CGFloat keyboardTop = keyboardRect.origin.y;

    CGFloat offset = self.normalTextField.frame.size.height + self.normalTextField.frame.origin.y - keyboardTop;

    NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSTimeInterval animationDuration;
    [animationDurationValue getValue:&animationDuration];

    if(offset > 0){
    // Animate the resize of the text view's frame in sync with the keyboard's appearance.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:animationDuration];

    CGRect rect = CGRectMake(0.0f, -offset,self.view.frame.size.width,self.view.frame.size.height);
    self.view.frame = rect;
    [UIView commitAnimations];
    }
    }
    1. 真机
      如果使用了中文输入法,注册的keyboardWillShow会回调两次。第一次是键盘默认高度216,第二次则是加了keyboard的导航栏的高度。

    2. 模拟器
      第一次弹出键盘没有问题

    打印userinfo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (lldb) po userInfo
    {
    UIKeyboardAnimationCurveUserInfoKey = 7;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {414, 226}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {207, 849}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {207, 623}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 736}, {414, 226}}";
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 510}, {414, 226}}";
    UIKeyboardIsLocalUserInfoKey = 1;
    }

    此时我们去按123旁边的小圆球会出现如下的图:

    打印userinfo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (lldb) po userInfo
    {
    UIKeyboardAnimationCurveUserInfoKey = 7;
    UIKeyboardAnimationDurationUserInfoKey = "0.25";
    UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {414, 271}}";
    UIKeyboardCenterBeginUserInfoKey = "NSPoint: {207, 623}";
    UIKeyboardCenterEndUserInfoKey = "NSPoint: {207, 600.5}";
    UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 510}, {414, 226}}";
    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 465}, {414, 271}}";
    UIKeyboardIsLocalUserInfoKey = 1;
    }

    键盘被遮挡了。

    总结:观察结果,发现了这个规律,打印一下时间,还有一个问题就是,中文键盘第一次启动的时候会回调两次。

    1
    keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

    所以去掉这句话即可

    六. 使用封装的XXTextField

    UITextView,UITextfield中如果有keyboard的时候,需要一个自动弹起事件,以及弹起之后的content的偏移对父view的处理。如果每个页面都实现一次会非常复杂。这里我们介绍一种自动化的处理机制。在此之前,先介绍一下文字处理框架.最后给大家推荐一下我写的XXTextField,大家也可以在此基础上自己添加一些正则表达式。使用方法很简单.欢迎加入QQ群:237305299 ,一起探讨iOS技术问题

    1.解决uiview中的textfield 遮挡问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    _textfieldName.keyboardType = UIKeyboardTypeDefault;
    _textfieldName.inputType = XXTextFieldTypeOnlyInt;
    _textfieldName.maxLength = 5;
    _textfieldPwd.inputType = XXTextFieldTypeForbidEmoj;

    #import "XXKeyboardManager.h"
    @interface XXCorrectVC ()<XXKeyboardManagerShowHiddenNotificationDelegate>
    @end

    @implementation XXCorrectVC

    - (void)viewDidLoad {
    [super viewDidLoad];
    [[XXKeyboardManager sharedInstance] setDelegate:self];
    // Do any additional setup after loading the view from its nib.
    }
    #pragma mark- KeyBoardShow/Hidden
    - (void)showKeyboardWithRect:(CGRect)keyboardRect
    withDuration:(CGFloat)animationDuration
    {
    CGFloat offset = self.textFieldCorrect.frame.size.height + self.textFieldCorrect.frame.origin.y - keyboardRect.origin.y;
    if(offset < 0){
    return;
    }
    [UIView animateWithDuration:animationDuration
    delay:0.f
    options:UIViewAnimationOptionCurveEaseInOut animations:^{
    CGRect rect = CGRectMake(0.0f, -offset,self.view.frame.size.width,self.view.frame.size.height);
    self.view.frame = rect;
    } completion:^(BOOL finished) {

    }];
    }

    - (void)hiddenKeyboardWithRect:(CGRect)keyboardRect
    withDuration:(CGFloat)animationDuration
    {
    [UIView animateWithDuration:animationDuration
    delay:0.f
    options:UIViewAnimationOptionCurveEaseInOut animations:^{
    self.textFieldCorrect.frame = self.view.bounds;
    } completion:^(BOOL finished) {
    }];
    }
    @end

    2.解决uitableview中键盘遮挡问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    /*
    * 键盘要显示的时候
    */
    - (void)showKeyboardWithRect:(CGRect)keyboardRect
    withDuration:(CGFloat)animationDuration{

    CGSize kbSize = keyboardRect.size;

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
    _baseTableView.contentInset = contentInsets;
    _baseTableView.scrollIndicatorInsets = contentInsets;

    // If active text field is hidden by keyboard, scroll it so it's visible
    // Your app might not need or want this behavior.
    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;

    if (!CGRectContainsPoint(aRect, _activeCell.frame.origin) ) {
    [_baseTableView scrollRectToVisible:_activeCell.frame animated:YES];
    }http://www.90168.org/
    }

    /*
    * 键盘要消失的时候
    */
    - (void)hiddenKeyboardWithRect:(CGRect)keyboardRect
    withDuration:(CGFloat)animationDuration{
    _baseTableView.contentInset = UIEdgeInsetsZero;
    _baseTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
    }
  • 相关阅读:
    [转载]ASP.NET实现数字和字符相混合的验证码
    [分享]软件开发全套规范
    [转载]混沌理论简介
    [原创]利用WM_COPYDATA实现进程间通信
    [转载]I like the subtle...
    [原创]DES算法的介绍以及实现(含上次DES程序1.0的源码)
    [转载]高校自动排课系统的实践
    [公告]对DES算法源码的bug道歉
    [转载]基于混沌理论的资本投资研究
    使用 异步多线程TCP Socket 实现进程间通信(VC 6.0 , BCB6.0调试通过)
  • 原文地址:https://www.cnblogs.com/tianshifu/p/6142900.html
Copyright © 2020-2023  润新知