[iOS]UITextField中secureTextEntry的几个小trick

背景

UITextField用的也够多了,这两天改一个“修改密码”的bug,结果发现一旦设置了secureTextEntry之后,会有很多的坑,
这里简单总结下:


第一天更新


// 说明:以下所有的问题点都是New Password这个UITextField

1. keyboard type会改变

背景:

设置当前New Password的keyboardtype是UIKeyboardTypeASCIICapable,

现象:

设置textfield为暗文的时候,正常;但是设置为明文的时候,键盘会变化,看如下截图(注意观察左下角):


这个原因也没查清楚,应该secureTextEntry切换的时候的bug.

那怎么解决呢?

简单来说,既然是明文状态下会出错,那么就在点击其他textfield的时候,将该password textfield设置为暗文即可.
即:可以监听textfield的textfield end edit 状态,并检查不是FirstResponder的时候,设置secureTextEntry为YES

解决代码如下:
- (void)textFieldChanged {
  if (![self.textField isFirstResponder]) {
      self.textField.secureTextEntry = YES;
  }
}

2. 光标不稳定

现象:

当secureTextEntry在YES和NO之间切换的时候,理论上光标应该在最后一个字符后面,但是实际会出现当有暗文变为明文的时候,光标还停留在原来的位置的情况.如下截图,蓝色光标和内容之间的空格:

那怎么解决呢?

这个的解决方法,想的比较容易,让光标重新刷新一下就好.
光标什么时候回刷新呢?
当输入的text改变的时候会刷新,于是考虑当设置secureTextEntry后, 将textfield重新赋值一次,即额外手动触发器一次text改变:

解决代码如下:
- (void)showPasswordAction {
  // fix cursor bug: reset text to refresh cursor
  NSString *tempStr = self.textField.text;
  self.textField.text = nil;
  self.textField.text = tempStr;

  [self setTextFiledSecureTextEntry:!self.textField.secureTextEntry];
}

3. text内容显示不全

现象:

光标移到其他textfield上,然后点击show的button,这时候就会出现部分字母显示不全的情况:


屏幕快照 2016-05-12 上午12.46.01.png

可当光标移到这个textfiled上的时候,就会恢复正常

那怎么解决呢?

如果要解决的话,比较简单的方式就是当点击show (就是这个"眼睛")这个button的时候,将光标移到当前textfield上.

解决代码如下:
- (void)showPasswordAction {
 // 这种代码一定要加注释,否则后面加入的同学要疯掉了...😢
  if (![self.textField isFirstResponder]) {
    [self.textField becomeFirstResponder];
  }
}
解决后:
屏幕快照 2016-05-12 上午12.46.13.png

4. 字体问题

现象:

password 和new password 设置的是相同的字体,但是会出现2者字体不一样的状态:


字体不对? 于是打了log看,发现本来设置的是系统字体,但是当光标移到password的时候,字体会变成new roman字体.
于是尝试再切换secureTextEntry的时候,重新再设置下字体

  //setLcFont 这个是我们自己定义的一个方法,无他尔...
  [self.textField setLcFont:[LcFont br17]];

But,
But!!!

Failed!
打了log看,设置后字体是需要的br17字体,但是实际显示的却是错误的字体

后来查了半天,才发现是一个iOS的bug:
可以参考http://stackoverflow.com/questions/35293379

那怎么解决呢?

  /* fix font bug:
   1.font will change when secureTextEntry changed
   2.iOS bug:font setting will not take effect until you  set the font to nil
   first
   */
  [self.textField setFont:nil];
  [self.textField setLcFont:[LcFont br17]];

因祸得福

当这个问题解决的时候,第二个光标刷新的问题也顺道解决了,
当然那个问题本质也应该是字体问题,刷新光标的解决方案也只是个trick技巧而已

以上,是昨天遇到的几个小问题
总结下代码就是:

屏幕快照 2016-05-12 上午1.23.28.png

第二天更新


5. 密码不显示省略号

今天又有新需求:

如下,当密码输入过多的时候,因为显示不下,所以会显示"..."
现在是希望,如果是明文密码,则可以显示"...",但如果是暗文,则不显示"..."


屏幕快照 2016-05-12 下午9.54.06.png

开玩笑,这怎么可能,UITextField不是UILabel,不可以设置line breaks, UILabel 可以设置的type如下:

// NSParagraphStyle
typedef NS_ENUM(NSInteger, NSLineBreakMode) {
    NSLineBreakByWordWrapping = 0,      // Wrap at word boundaries, default
    NSLineBreakByCharWrapping,  // Wrap at character boundaries
    NSLineBreakByClipping,  // Simply clip
    NSLineBreakByTruncatingHead, // Truncate at head of line: "...wxyz"
    NSLineBreakByTruncatingTail, // Truncate at tail of line: "abcd..."
    NSLineBreakByTruncatingMiddle // Truncate middle of line:  "ab...yz"
} NS_ENUM_AVAILABLE(10_0, 6_0);

但UITexField没有这个属性,查了半天,也是相关UITexField搞不定的用UITextView,但那是适用于多行显示的问题,与本问题无关.

几经周折("人和人的区别就在这里...")

终于搞定.

那怎么解决呢?

解决方案:
根据textfield的text的内容动态调整期frame,这样就不会出现"..."了 (出现截断的本质是因为width不够,那就增加宽度就好)

当然修改text的frame,这个方法隐藏的比较深了...

- (CGRect)textRectForBounds:(CGRect)bounds {
  // Not show truncation text for secureTextEntry,like ****...
  if (self.text.length > 0) {
    if (self.secureTextEntry && ![self isFirstResponder]) {
      CGRect rect = bounds;
      CGSize textSize = [self.text sizeOfFont:self.font andWidth:CGFLOAT_MAX];
      rect.size.width = MAX(textSize.width, bounds.size.width);
      return rect;
    }
  }
  return [super textRectForBounds:bounds];
}

解释下:

- (CGRect)textRectForBounds:(CGRect)bounds:
lets you set the rectangle for the text when the text field is not being edited.

- (CGRect)editingRectForBounds:(CGRect)bounds:
lets you set the rectangle for the text when the text field is being edited.


//  重写绘制行为 
# 除了UITextField对象的风格选项,
# 你还可以定制化UITextField对象
# 为他添加许多不同的重写方法,来改变文本字段的显示行为。
# 这些方法都会返回一个CGRect结构
# 制定了文本字段每个部件的边界范围。以下方法都可以重写。 
      
    
– textRectForBounds:     //重写来重置文字区域      
– drawTextInRect:         //改变绘文字属性.
//重写时调用super可以按默认图形属性绘制,若自己完全重写绘制函数,就不用调用super了. 
     
– placeholderRectForBounds:  //重写来重置占位符区域 
– drawPlaceholderInRect:     //重写改变绘制占位符属性.
//重写时调用super可以按默认图形属性绘制,若自己完全重写绘制函数,就不用调用super了. 
     
– borderRectForBounds:  //重写来重置边缘区域 
– editingRectForBounds:  //重写来重置编辑区域 
– clearButtonRectForBounds: //重写来重置clearButton位置,改变size可能导致button的图片失真 
    
– leftViewRectForBounds:      
– rightViewRectForBounds: 
    

结果如下:


屏幕快照 2016-05-12 下午10.26.03.png

参照 http://stackoverflow.com/questions/3287312


第三天更新


6. placeholder 的字体问题

6.1 背景:

大家不知是否记得我们的第四条字体问题,为了修改字体,使用了如下方法:

[self.textField setFont:nil];
[self.textField setLcFont:[LcFont br17]];

这个本来安心的交给测试了,结果产生了新的问题:

6.2 现象:

这个方法会改变placeholder的字体:

默认情况:

屏幕快照 2016-05-13 下午3.37.36.png

当什么都不输入,直接点击眼睛:

(即执行如上setLcFont设置字体的操作之后)

屏幕快照 2016-05-13 下午3.37.45.png

大家可以看到"6-20 characters" 这个字符变小了.

至于为什么会发生这个,很显然是个苹果的bug,
首先通过先设置为nil再设置字体的方式,本身就很诡异,自然会引发出新的问题.
目前表现就是placeholder的字体不对了

6.3 那怎么解决呢

那我们就看下怎么修改placeholder的字体,

6.3.1 attributeString

大概看了下,常见思路就是,设置attributestring,这个看上去可以,但是得把代码中所有的都这么改,而且attribute本身设置起来--"又臭又长",不太实用
所以pass.

6.3.2 placeholderLabel

placeholder 本质是个label,
有个比较常见的设置placeholder color的方法:

[textfield setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];

当然这个函数也直接可以通过xcode进行设置完成.


屏幕快照 2016-05-13 下午5.03.34.png

但这个有人反馈自己因为这个被APPSTORE拒绝过.
所以还是pass

6.3.3 自己来渲染
6.3.3.1 textRectForBounds启发

昨天有介绍过textRectForBounds这个方法,那自然对应也有placeholder相关的方法:

/*
Draws the receiver’s placeholder text in the specified rectangle.

You should not call this method directly. 
If you want to customize the drawing behavior for the placeholder text, 
you can override this method to do your drawing.

By the time this method is called, the current graphics context is already configured with the default environment and text color for drawing. 
In your overridden method, you can configure the current context further and then invoke super to do the actual drawing or do the drawing yourself. 
If you do render the text yourself, you should not invoke super.
*/
 - (void)drawPlaceholderInRect:(CGRect)rect {}

这个如果你完全自己定义placeholder的text,那就不需要调用super方法,否则建议不然忘记super方法.

6.3.3.2 实现drawPlaceholderInRect

show me the code:

- (void)drawPlaceholderInRect:(CGRect)rect {
    //draw place holder.
   [[self placeholder] drawInRect:rect withFont:[UIFont systemFontOfSize:17]];

}

okey,这样一来,字体就保证了,但是run起来会发现,字体的颜色和位置不对了 ---- 始终处于置顶的感觉


屏幕快照 2016-05-13 下午4.46.11.png
6.3.3.3 解决对齐问题

颜色的问题好解决,我们先来看看置顶的问题:

  1. 调整垂直对齐方式
    如下:
  self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;

发现无效. 然后依次设置了如下全部ContentVerticalAlignment对齐方式后,只有AlignmentBottom会置底,其他都会置顶.

typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
    UIControlContentVerticalAlignmentCenter  = 0,
    UIControlContentVerticalAlignmentTop     = 1,
    UIControlContentVerticalAlignmentBottom  = 2,
    UIControlContentVerticalAlignmentFill    = 3,
};
UIControlContentVerticalAlignmentBottom
  1. drawInRect
    前面的不行,那只能从drawInRect下手了,这里断点查了下rect如下:
    print rect

    截图可以看到y = 0,所以导致无法居中,猜想super的
    drawPlaceholderInRect方法里面应该是做了一些对齐的操作,那我们也自己来实现一下吧,这个倒是不难
  CGSize size = [self.placeholder sizeOfFont:self.font andWidth:CGFLOAT_MAX];
  CGRect placeholderRect =
      CGRectMake(rect.origin.x, (rect.size.height - size.height) / 2,
                 rect.size.width, size.height);

参照http://stackoverflow.com/questions/19093604

  1. 还差一点
    在‘2’的基础上测试之后,发现位置是终于居中了,但是点击"eye" buton的时候,位置还是会稍微的有一点点偏移,查了下代码,如果rect会有改变,应该是UITextfied在你编辑状态和非编辑状态的时候,位置会有一定的出入(这个稍微留心点,都能发现)
    所以我们的代码还需要再做一丁点的改变:
  CGRect placeholderRect =
      CGRectMake(rect.origin.x, (self.height - size.height) / 2,
                 rect.size.width, size.height);

再测试一下,okey.

6.3.3.3 解决颜色问题

这个没什么方法,扣色调整下就行,不过整体扣色还是不太准确,需要自己再去调试.

比较常见的颜色是

[UIColor colorWithWhite:0.70 alpha:1]

不过我试下来,感觉还是不对,自己调整了,大概颜色是:

[UIColor colorWithHexString:@"CDCDC8"] colorWithAlphaComponent:0.8]

不过这个不是重点了,找自己家里的UI去做就好了...

6.4 最终代码

屏幕快照 2016-05-13 下午5.19.16.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容