长度限制用到的地方很多,但是需求都不一样.有的要求全部字符按一个处理,有的要求英文字母按一个,中文按两个,emoji按四个.这样就会遇到各种各样奇怪的问题,再被虐了无数次后,终于解决掉了.下面就来写写遇到的各种坑.

Delegate

首先想到的方法肯定是delegate:

#define kMaxLength 10
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if (textField.text.length > kMaxLength) {
return NO;
}
return YES;
}

结果运行下来有问题,输到第10为的时候连删除也没法接收了,这样肯定不行.于是想到了每次都让它输进去,之后截取到第10位.

#define kMaxLength 10
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *toString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if (toString.length > kMaxLength) {
textField.text = [toString substringToIndex:kMaxLength];
return NO;
}
return YES;
}

简单地测试了下发现没什么问题,不过稍微细致点就发现了两个问题:

  • 输入结束后,点击输入框上面的候选汉字,不会进入委托,可以无限的长.
  • 当使用拼音输入法时,输入的汉字默认两个字符长度,当你输入到上方候选汉字有6位时,实际上还没超过长度,但是已经无法输入,框里也变成了输入的字母,十分不方便.

之后网上查了很多,有在delegate里实现,感觉很复杂.还是用UITextInputCurrentInputModeDidChangeNotification来做更方便点.

Notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textField_textDidChange:) name:UITextFieldTextDidChangeNotification object:textF];

#define kMaxLength 10
- (void)textField_textDidChange:(NSNotification *)notification {
UITextField *textField = (UITextField *)notification.object; NSString *toBeString = textField.text;
UITextRange *selectedRange = [textField markedTextRange];
//获取高亮部分
UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
// 没有高亮选择的字,则对已输入的文字进行字数统计和限制
if (!position) {
if (toBeString.length > kMaxLength) {
textField.text = [toBeString substringToIndex:kMaxLength];
}
}
// 有高亮选择的字符串,则暂不对文字进行统计和限制
else{ }
} - (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

输入框上面的高亮部分可以无限输,只是长度变化的时候截取.只是有个瑕疵,就是高亮部分可以无限输入.

emoji表情截取

本来以为万事大吉了,但是测试还是挑出了bug,当前面输入的是字母,最后一个是表情时,表情会被截取,成为一个很奇怪的符号.

原来问题出在了substringToIndex这个方法上.怎么得出这个结论的呢:

-(unichar)characterAtIndex:(NSUInteger)index
typedef unsigned short unichar;

这个方法的返回值unichar是个16位的无符号整型.那么所有对NSString的index位置操作,都是以unichar为单位的.

查阅字符编码可以发现:

例如这个emoji表情,字符编码为:

Unicode: U+1F601 (U+D83D U+DE01)

发现了问题所在了,emoji表情有20位啊,16位的unichar根本存不下!原来Unicode编码最初是被设计为16位的,后来为了编码一些冷门的中文日文,Unicode编码扩展到了21位(从U+0000到 U+10FFFF).

原因是找到了,怎么解决呢?

NSString与Unicode,这篇文章把我所有的困惑都解决了,并且附上了解决办法.真要感谢下objc中国,不然让我看原版英文,估计够呛,英文还是不能丢啊!

//通知的方法
#define kMaxLength 8
- (void)textField_textDidChange:(NSNotification *)notification {
UITextField *textField = (UITextField *)notification.object; NSString *toBeString = textField.text;
UITextRange *selectedRange = [textField markedTextRange];
//获取高亮部分
UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
// 没有高亮选择的字,则对已输入的文字进行字数统计和限制
if (!position) {
if (toBeString.length > kMaxLength) {
UITextRange *textRange = textField.selectedTextRange;
textField.text = [toBeString subStringWithMaxLength:kMaxLength];
textField.selectedTextRange = textRange;
}
}
// 有高亮选择的字符串,则暂不对文字进行统计和限制
else{ }
} @implementation NSString (Add)
- (NSString *)subStringWithMaxLength:(NSInteger)maxLength {
__block NSString *aString = @"";
__block int length = 0;
[self enumerateSubstringsInRange:NSMakeRange(0, self.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
char *p = (char *)[substring cStringUsingEncoding:NSUnicodeStringEncoding];
for (int i = 0; i < [substring lengthOfBytesUsingEncoding:NSUnicodeStringEncoding]; i++) {
if (*p && p != '\0') {
length++;
}
p++;
}
if (length <= maxLength) {
aString = [aString stringByAppendingString:substring];
}
}]; return aString;
}
@end

重写个NSString截取方法,以后每次截取都用这个方法,就可以解决最后一个表情被截的问题了.

总结

相信很多人都被产品经理虐过,例如textView,两边文字内的间距调整,增加placeholder,设置placeholder的字体颜色,或者上文讲的文字不超过多少等等.

被虐过千百回,大多数情况也都遇到过了,特地封装了两个category,是textField和textView,基本上解决了大多数状况,只需要设置属性值就行了:

    tv.maxLength = 20;
tv.placeholder = @"我是textView";
tv.placeholderFont = [UIFont systemFontOfSize:15];
tv.placeholderColor = [UIColor redColor];

是不是很方便,github地址,欢迎大家交流,提出产品经理的要求,继续完善.

UITextFiled,UITextView长度限制的更多相关文章

  1. ios 浅谈一下UITextFiled UITextView 在tableview的cell上边展示

    最近在项目中.要做到在tableview的cell上边加一个输入框.允许用户输入. 1.我首先选的是在uitextView  然后在通知键盘出现的时候,将tableview的内容设置在键盘的上边.但是 ...

  2. iOS 之UITextFiled/UITextView小结

    一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...

  3. 监听UITextFiled输入文字长度的变化

    需求:如果UITextFiled文字的长度大于零,改变一个按钮的颜色 1.一开始想到的当然是UITextFiled的代理方法,但是在UITextFiled的代理方法中并没有监听这个的这一选项!!! 2 ...

  4. UITextView 输入长度限制

    //还可以输入的长度. - (void)textViewDidChange:(UITextView *)textView { UITextRange *markRange = textView.mar ...

  5. 谈论multistage text input(中国输入法)下一个UITextView内容长度的限制

    我以前写<如何更好地限制UITextField输入长度>.接使用 UIKIT_EXTERN NSString *const UITextFieldTextDidChangeNotifica ...

  6. 当cell中有UItextfiled或者UITextVIew时,弹出键盘把tableview往上,但是有的cell没有移动

    cell中有UITextView时,输入文字是需要将tableView向上移,基本的做法是,注册键盘变化的通知在通知的方法中做tableVIew的位置调整, 一,一般做法 - (void)regist ...

  7. TextField和TextView的限制输入长度

    TextField的限制代理方法 只需要在这个代理方法里面code这样的代码就可以了 16 是长度可以自己设置 - (BOOL)textField:(UITextField *)textField s ...

  8. UITextView 点击添加文字 光标处于最后方

    #import "ViewController.h" @interface ViewController ()<UITextViewDelegate> @end @im ...

  9. UITextView的使用详解

    //初始化并定义大小 UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(20, 10, 280, 30)]; te ...

随机推荐

  1. 我如何调优SQL Server查询

    我是个懒人,我只想干尽可能少的活.当我干活的时候我不想太多.是,你没看错,这看起来很糟糕,作为一个DBA这很不合格.但在今天的文章里,我想给你展示下,当你想对特定查询创建索引设计时,你如何把你的工作和 ...

  2. Wo的书单

    一个人,一生之中总要有几本证明自己的书. 2016---08 <ASP.NET MVC5 高级编程(第五版)> <数据结构(C语言第二版)>

  3. 微信开发jssdk入门

    一个项目需要在微信里获得当前位置,于是就开始了我的微信开发之旅... 微信JSSDK说明文档http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9 ...

  4. Clr编写Insert Triggr

    在CLR编写一个插入娄据的触发器. 这个触发器是当对表插入数据时,即时把刚才插入的数据显示出来: 可复制代码: public static void tri_RetrieveJustInsertedD ...

  5. Mssql中一些常用数据类型的说明和区别

    Mssql中一些常用数据类型的说明和区别 1.bigint 占用8个字节的存储空间,取值范围在-2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,37 ...

  6. C#的变迁史 - C# 3.0篇

    C# 3.0 (.NET 3.5, VS2008) 第三代C#在语法元素基本完备的基础上提供了全新的开发工具和集合数据查询方式,极大的方便了开发. 1. WPF,WCF,WF 这3个工程类型奠定了新一 ...

  7. 项目中的web api知识总结

    最近在做公司的项目,自己负责webapi的框架的搭建与开发,最近很忙,一直没时间对工作中遇到的知识点缺少个总结,现总结一下,对自己是个提升,如果个人的小点点小总结能对博友有帮助那也是善莫大焉. (1) ...

  8. 不可或缺 Windows Native (25) - C++: windows app native, android app native, ios app native

    [源码下载] 不可或缺 Windows Native (25) - C++: windows app native, android app native, ios app native 作者:web ...

  9. hibernate----N-N--(人与地点)

    package com.ij34.dao; import java.util.HashSet; import java.util.Set; import javax.persistence.*; @E ...

  10. Mac 连接阿里云服务器

    1. 通过命令行连接 Server 并设置 1.1 连接 Server #: ssh root@hctec.top ssh: 远程连接工具 root: 远程服务器用户名, 此处我用的是: root 用 ...