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

2334471588 2年前
   <p>UITextView , UITextfield 中有很多坑,网上的方法也很多。但是并不是很全面吧,这里全面进行了总结,并进行了封装。欢迎大家下载。</p>    <h3><strong>一. 字符限制</strong></h3>    <p><strong>1. 错误方法</strong></p>    <p>常见的这种方法是错误的,会导致Emoj表情的截取问题</p>    <pre>  <code class="language-objectivec">- (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;  }  </code></pre>    <p>这种限制方法会导致拼音下出现这种情况,且无法输入.无法输入满5个字符。在emoj表情也有问题</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e9246319ca4939fed488269d817ed79f.jpg"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6efc4b881d298ea92c9b7a48e398bb31.jpg"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/00ea5cc58b00e67764f80b343cded1d0.jpg"></p>    <p><strong>2. 推荐方法</strong></p>    <p>使用rangeOfComposedCharacterSequencesForRange, 防止在range范围内整词被截断</p>    <pre>  <code class="language-objectivec">- (void)textFieldDidChange:(UITextField *)textField  {      NSString *toBeString = textField.text;        UITextRange *selectedRange = [textField markedTextRange];      UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];            // 没有高亮选择的字,则对已输入的文字进行字数统计和限制,防止中文被截断      if (!position){          if (toBeString.length > _maxLength){              //中文和emoj表情存在问题,需要对此进行处理              NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, _maxLength)];              textField.text = [toBeString substringWithRange:rangeRange];          }      }  }  </code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/bd83777889157c3fbf64e07ef2fdf673.jpg"></p>    <h3><strong>二. 字节限制</strong></h3>    <p><strong>1. 限制字节数</strong></p>    <p>在UTF8中,英文和数字是1个字节,汉子是3个字节,emoji是3或者4个字节。这里的难度比上面更大,如果截取失败,极有可能出现乱码。这里我们的做法如下</p>    <pre>  <code class="language-objectivec">- (void)textFieldDidChange:(UITextField *)textField  {      NSString *toBeString = textField.text;      //---字节处理   NSInteger bytesCount = strlen([textField.text UTF8String]);   if (bytesCount > _maxBytesLength) {     NSString *content = [textField.text subStrWithUtf8Len:(int)_maxBytesLength];     textField.text = content;   }  }    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{            NSString * inputString = [textField.text stringByReplacingCharactersInRange:range withString:string];            //限制字节数      if ([inputString length] > 0){          NSInteger len = strlen([inputString UTF8String]);          if (len > _maxBytesLength){              return NO;          }          else {              return  YES;          }      }     return YES;  }  </code></pre>    <p>这里不能只在进行限制,在textFieldDidChange中需要对中文联想做处理才行</p>    <h3><strong>三. 放弃键盘</strong></h3>    <p><strong>1. 能拿到uitextfield的时候用</strong></p>    <pre>  <code class="language-objectivec">- (BOOL)textFieldShouldReturn:(UITextField *)textField  {      return [textField resignFirstResponder];  }  </code></pre>    <p>2. 点击view消失的时候用</p>    <pre>  <code class="language-objectivec">[self.view endEditing:YES];  </code></pre>    <p>3. 难以获取的时候用</p>    <pre>  <code class="language-objectivec">[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];  </code></pre>    <p>或者</p>    <pre>  <code class="language-objectivec">[[[UIApplication sharedApplication] keyWindow] endEditing:YES];  </code></pre>    <p><strong>2.Tableview点击空白处或者滚动时消失</strong></p>    <pre>  <code class="language-objectivec">{      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];  }  </code></pre>    <h3><strong>四. 正则表达式限制</strong></h3>    <p>请参考 正则表达式语法表 ,这里我提供了两种表达式给大家参考,一个Int,一个无unsignedInt</p>    <pre>  <code class="language-objectivec">-(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]+"];  }  </code></pre>    <h3><strong>五. UITextfield的键盘事件多次回调问题</strong></h3>    <p><strong>1.键盘高度遮挡问题</strong></p>    <p>一般出现遮挡的时候我们用以下代码,看看当前textfield是否在键盘下面,在的话算出键盘的顶端和textfield的底部的距离,然后做偏移动画</p>    <pre>  <code class="language-objectivec">- (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];      }  }  </code></pre>    <ol>     <li> <p>真机</p> <p>如果使用了中文输入法,注册的keyboardWillShow会回调两次。第一次是键盘默认高度216,第二次则是加了keyboard的导航栏的高度。</p> </li>     <li> <p>模拟器</p> <p>第一次弹出键盘没有问题</p> </li>    </ol>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e0923a0f2fa276e1eaac2c4b21667f4b.png"></p>    <p>打印userinfo:</p>    <pre>  <code class="language-objectivec">(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;  }  </code></pre>    <p>此时我们去按123旁边的小圆球会出现如下的图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/08006c07364dded2bcba7db8d2966b8f.png"></p>    <p>打印userinfo:</p>    <pre>  <code class="language-objectivec">(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;  }  </code></pre>    <p>键盘被遮挡了。</p>    <p>总结:观察结果,发现了这个规律,打印一下时间,还有一个问题就是,中文键盘第一次启动的时候会回调两次。</p>    <pre>  <code class="language-objectivec">keyboardRect = [self.view convertRect:keyboardRect fromView:nil];  </code></pre>    <p>所以去掉这句话即可</p>    <h3><strong>六. 使用封装的XXTextField</strong></h3>    <p>UITextView , UITextfield 中如果有keyboard的时候,需要一个自动弹起事件,以及弹起之后的content的偏移对父view的处理。如果每个页面都实现一次会非常复杂。这里我们介绍一种自动化的处理机制。在此之前,先介绍一下文字处理框架.最后给大家推荐一下我写的 XXTextField ,大家也可以在此基础上自己添加一些正则表达式。使用方法很简单.欢迎加入QQ群:237305299 ,一起探讨iOS技术问题</p>    <p><strong>1.解决uiview中的textfield 遮挡问题</strong></p>    <pre>  <code class="language-objectivec">_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  </code></pre>    <p><strong>2.解决uitableview中键盘遮挡问题</strong></p>    <pre>  <code class="language-objectivec">/*   * 键盘要显示的时候   */  - (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];      }  }    /*   * 键盘要消失的时候   */  - (void)hiddenKeyboardWithRect:(CGRect)keyboardRect                    withDuration:(CGFloat)animationDuration{      _baseTableView.contentInset = UIEdgeInsetsZero;      _baseTableView.scrollIndicatorInsets = UIEdgeInsetsZero;  }  </code></pre>    <p> </p>    <p>来自:http://www.iosxxx.com/blog/2016-11-27-UITextField最大字符数和最大字节数的限制.html</p>    <p> </p>