iOS UITextField最大字符数和字节数的限制详解

 更新时间:2016年11月30日 08:47:28   投稿:daisy  
在开发中我们经常遇到这样的需求:在UITextField或者UITextView中限制用户可以输入的最大字符数。但在UITextView , UITextfield 中有很多坑,网上的方法也很多。但是并不是很全面吧,这里全面进行了总结,有需要的朋友们可以参考借鉴,下面跟着小编一起来学习学习吧。

前言

这里我给大家几组测试用例可以一试,为啥不好用。

     1、限制10个字节,输入2个Emoj之后是8个字节(一个Emoj是4个字节),此时再输入一个中文,看看结果如何(中文的UTF8占3个字节)

     2、限制5个字符,一个Emoj是2个字符,其他都是一个。此时输入两个Emoj,再输入中文,然后中文联想试试。

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

一. 字符限制

1. 错误方法

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

- (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范围内整词被截断

- (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];
 }
 }
}

二. 字节限制

1. 限制字节数

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

- (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;
}

这里不能只在进行限制,在textFieldDidChange中需要对中文联想做处理才行

三. 放弃键盘

1. 能拿到uitextfield的时候用

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

2. 点击view消失的时候用

[self.view endEditing:YES];

3. 难以获取的时候用

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

或者

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

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

{
 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

-(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的底部的距离,然后做偏移动画

- (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:

(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:

(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;
}

键盘被遮挡了。

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

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

所以去掉这句话即可

六. 使用封装的XXTextField

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

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

_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中键盘遮挡问题

/*
 * 键盘要显示的时候
 */
- (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;
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位Android开发者们能有所帮助,如果有疑问大家可以留言交流。

相关文章

  • iOS动态验证码实现代码

    iOS动态验证码实现代码

    本文通过实例代码给大家介绍了ios动态验证码的实现方法,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2018-04-04
  • iOS UISearchController的使用方法

    iOS UISearchController的使用方法

    本文主要介绍了iOS UISearchController的使用方法,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • IOS开发之路--C语言存储方式和作用域

    IOS开发之路--C语言存储方式和作用域

    只有你完全了解每个变量或函数存储方式、作用范围和销毁时间才可能正确的使用这门语言。今天将着重介绍C语言中变量作用范围、存储方式、生命周期、作用域和可访问性。
    2014-08-08
  • iOS定时器的选择CADisplayLink NSTimer和GCD使用

    iOS定时器的选择CADisplayLink NSTimer和GCD使用

    这篇文章主要为大家介绍了iOS定时器的选择CADisplayLink NSTimer和GCD使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • iOS如何优雅地实现序列动画详解

    iOS如何优雅地实现序列动画详解

    这篇文章主要给大家介绍了关于iOS如何优雅地实现序列动画的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • IOS 实现3D 浮动效果动画

    IOS 实现3D 浮动效果动画

    这篇文章主要介绍了IOS 实现3D 浮动效果动画的相关资料,需要的朋友可以参考下
    2016-09-09
  • 30分钟快速带你理解iOS中的谓词NSPredicate

    30分钟快速带你理解iOS中的谓词NSPredicate

    NSPredicate类是用来定义逻辑条件约束的获取或内存中的过滤搜索。下面这篇文章将通过30分钟快速带大家理解iOS中的谓词NSPredicate类,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-03-03
  • iOS关闭虚拟键盘方法汇总

    iOS关闭虚拟键盘方法汇总

    在iOS应用开发中,有三类视图对象会打开虚拟键盘,进行输入操作,但如何关闭虚拟键盘,却没有提供自动化的方法
    2016-04-04
  • iOS实现H5支付(微信、支付宝)原生封装

    iOS实现H5支付(微信、支付宝)原生封装

    这篇文章主要介绍了iOS实现H5支付(微信、支付宝)原生封装,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • 轻松搞定iOS远程消息推送

    轻松搞定iOS远程消息推送

    这篇文章主要帮助大家轻松搞定iOS远程消息推送,讨论远程推送的流程与配置过程,感兴趣的小伙伴们可以参考一下
    2016-09-09

最新评论