UITextFiled文字抖动效果

最终设置UITextField的placeholder效果:


有需求1如下:

  • 未点击时UITextField的placeholder为浅灰色
  • 点击后,还未进行输入时,UITextField的placeholder变为深灰色

    这个实现并不难:

  • 通过通知或者重写UITextField的响应者处理方法,都可以实现捕获点击时间

  • UITextField设置placeholder可以使用以下属性:
    • 通过设置这个富文本属性,可以得到丰富多彩的placeholder
1
2
3
4
@NSCopying var attributedPlaceholder: NSAttributedString?

// 附带光标颜色属性
var tintColor: UIColor!

但是需求2加了点东西:

  • 点击后,还未进行输入时,UITextField的placeholder文字左右进行小幅度抖动

可以看到通过设置attributedPlaceholder,可以改变一些静态的属性,如颜色和文字大小。

但是如果需要里面的文字做一些简单的抖动效果貌似就不行了,UITextField没有提供相关属性,我们也不知道placeholder是在何种控件中显示的。

既然不知道laceholder是在何种控件中显示,那就通过以下代码打印出UITextField中所有的成员变量(函数参考runtime基础元素解析),看看是否会有什么发现:

1
2
3
4
5
6
7
8
9
Ivar *ivars = class_copyIvarList([UITextField class], &outCount);

for (int i = 0; i < outCount; i++) {
Ivar ivar = ivars[i];

NSLog(@"%s", ivar_getName(ivar));
}

free(ivars);

截取关键部分如下:


从字面上看,上面的_placeholderLabel是否就是显示placeholder的控件?

测试实际结果的确是显示placeholder的控件。

只要有了这个控件,那要做一些小抖动的动画那就没什么问题了,先获取这个UILabel:

1
2
3
4
5
private var tpcPlaceholderLabel:UILabel? {
get {
return self.valueForKey("_placeholderLabel") as? UILabel
}
}

然后重写UITextField的响应者处理函数:

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
46
47
// 成为第一响应者
override func becomeFirstResponder() -> Bool {

// 存储正常颜色
if normalColor == nil {
normalColor = tpcPlaceholderLabel?.textColor
}
// 存储选中颜色
if selectedColor == nil {
selectedColor = tpcPlaceholderLabel?.textColor
}

tpcPlaceholderLabel?.textColor = selectedColor

// 执行placeholder动画函数
placeholderLabelDoAnimationWithType(animationType)

return super.becomeFirstResponder()
}

// 放弃第一响应者
override func resignFirstResponder() -> Bool {

switch animationType {
case .TPCAnimationTypeUpDown :
fallthrough
case .TPCAnimationTypeBlowUp :
fallthrough
case .TPCAnimationTypeLeftRight :
tpcPlaceholderLabel?.transform = CGAffineTransformIdentity
case .TPCAnimationTypeEasyInOut :
UIView.animateWithDuration(0.5, animations: { () -> Void in
tpcPlaceholderLabel?.alpha = 1.0
})
case .TPCAnimationTypeNone :
break
}

if let operate = operateWhenResignFirstResponder {
operate()
}

// 设置为初始颜色
tpcPlaceholderLabel?.textColor = normalColor

return super.resignFirstResponder()
}

然后通过以下函数,传入相应的动作就可以得到抖动的效果了

1
2
3
4
5
private func doAnimation(action: () -> ()) {
UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.1, initialSpringVelocity: 10, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
action()
}, completion: nil)
}

还有一点,根据上面打印的UITextField成员变量,看到了_displayLabel,这个就是在键盘输入后显示文字的UILabel了。这个属性可以用来干嘛?

我想,可能会有这么一种需求(不过可能没有),就是用户输入错误时,UITextField中已经输入的文字做左右抖动,以间接的形式,辅助提醒用户,这一栏输错了,而不是弹出一个HUB

由于UITextField内部做了某些处理,所以无法在成为第一响应者时做一些动作,那么,就在放弃第一响应者函数中。

相关代码如下:

1
2
3
4
5
6
7
// 设置一个在放弃第一响应者的闭包属性
var operateWhenResignFirstResponder: (() -> ())?

// 在func resignFirstResponder() -> Bool函数中调用
if let operate = operateWhenResignFirstResponder {
operate()
}

代码地址: UITextFiled文字抖动效果