前言
这里我给大家几组测试用例可以一试,为啥不好用。
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范围内整词被截断
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
- ( 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个字节。这里的难度比上面更大,如果截取失败,极有可能出现乱码。这里我们的做法如下
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 *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的时候用
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]; |
4.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 ,大家也可以在此基础上自己添加一些正则表达式。
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]; } } /* * 键盘要消失的时候 */ - ( void )hiddenkeyboardwithrect:(cgrect)keyboardrect withduration:(cgfloat)animationduration{ _basetableview.contentinset = uiedgeinsetszero; _basetableview.scrollindicatorinsets = uiedgeinsetszero; } |
总结
以上就是这篇文章的全部内容了,希望本文的内容对各位android开发者们能有所帮助,如果有疑问大家可以留言交流。