UITextView,UITextfield中有很多坑,网上的方法也很多,但是用过之后暂时没有发现一个好用。这里我给大家几组测试用例可以一试,为啥不好用。
- 限制10个字节,输入2个Emoj之后是8个字节(一个Emoj是4个字节),此时再输入一个中文,看看结果如何(中文的UTF8占3个字节)
- 限制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]; } }
|
真机
如果使用了中文输入法,注册的keyboardWillShow会回调两次。第一次是键盘默认高度216,第二次则是加了keyboard的导航栏的高度。
模拟器
第一次弹出键盘没有问题

打印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; }
|
- Java中文字符所占的字节数
Java语言中,中文字符所占的字节数取决于字符的编码方式,一般情况下,采用ISO8859-1编码方式时,一个中文字符与一个英文字符一样只占1个字节:采用GB2312或GBK编码方式时,一个中文字符占2 ...
- Notepad++查看文本文件的总的字符数、GBK字节数、UTF8字节数
如果其编码是 小结:UTF-8编码下,一个汉字占3字节,GBK编码下,一个汉字占2字节:
- 关于char/varchar(n)中n的探究:字符数or字节数
[问题来源]将设计的数据库表展示的时候,yu哥问我,你的那个top_info字段定义的类型是varchar(100),为什么是100呢,这100的长度能存多少个中文? 当时的想法就是,这个100能存多 ...
- Java字符串中常用字符占用字节数
java中一个char型的数据(也就是一个字符)占两个字节.而Java中常用的字符包括数字.英文字母.英文符号.中文汉字.中文符号等,若在字符串中包含里面的多种字符,它们是否都占两个字符呢?答案是否定 ...
- Java不同编码方式,中英文字符所占字节数
测试代码 public class Test { public static void main(String[] args){ String[] charsetNames={ "UTF-8 ...
- UITextView 和 UITextField限制字符数和表情符号
UITextField限制字符数 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)r ...
- JS计算字符长度、字节数 -- 转
一个汉字在UTF-8编码中占用几个字节? 占用3个字节的范围 U+2E80 - U+2EF3 : 0xE2 0xBA 0x80 - 0xE2 0xBB 0xB3 共 115 个 U+2F00 - U+ ...
- Java中字符编码和字符串所占字节数 .
首 先,java中的一个char是2个字节.java采用unicode,2个字节来表示一个字符,这点与C语言中不同,C语言中采用ASCII,在大多数 系统中,一个char通常占1个字节,但是在0~12 ...
- 编码占用的字节数 1 byte 8 bit 1 sh 1 bit 中文字符编码 2. 字符与编码在程序中的实现 变长编码 Unicode UTF-8 转换 在网络上传输 保存到磁盘上 bytes
小结: 1.UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等: 2 服务器->网页 utf-8 ...
随机推荐
- CSS实现限制显示的字数,超出显示"..."
一.背景 在实际项目中,我们常常需要对某些页面的某些特定区域显示指定数量的内容,超出的内容显示"..."来进行美化页面,那么应该怎么做呢?今天就让我们来看看如何达到这一效果. 二. ...
- Ios cordova安装
安装NODEJS:http://nodejs.org/ (如果你安装了旧版本的需要手动安装npm,不过最新版的自带了) 进入终端命令行使用npm安装cordova如下: $ sudo npm inst ...
- [Android Pro] app_process command in Android
reference to : http://blog.csdn.net/wangkaiblog/article/details/46050587 本来以为存放在/systen/bin/下的monkey ...
- Codeforces Round #344 (Div. 2)(按位或运算)
Blake is a CEO of a large company called "Blake Technologies". He loves his company very m ...
- postgresql导入及导出
导入命令 psql -d GAME -U postgres -f /root/plubic.sql 出现如下错误: psql: FATAL: Peer authentication failed f ...
- LoadRunner 思考时间与事务响应时间的区别与关系
LoadRunner 思考时间与事务响应时间的区别与关系 思考时间lr_think_time 就是一个事务要开始时思考的时间;比如 你要点击一个 登录按钮 我们都要点击这个按钮要先思考下 就是人为 ...
- JavaWeb学习之JSTL自定义标签库的使用、JSTL自定义函数库(7)
一.自定义标签,步骤 * 确定需求 * <my:date /> 输出当前系统的时间 yyyy-MM-dd hh:mm:ss:SSS * 编写Java类 新建包名:com.yxl.tag,新 ...
- HTML5学习之画布和SVG(四)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- hdu 1754:I Hate It(线段树,入门题,RMQ问题)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- 百度编辑器UEditor ASP.NET示例Demo 分类: ASP.NET 2015-01-12 11:18 346人阅读 评论(0) 收藏
在百度编辑器示例代码基础上进行了修改,封装成类库,只需简单配置即可使用. 完整demo下载 版权声明:本文为博主原创文章,未经博主允许不得转载.