問題
UITextField作為輸入常用控件,但是問題卻很多,本篇主要用于解決以下兩個(gè)問題。
- 輸入時(shí)文字位置自動(dòng)下移;
- 自動(dòng)布局時(shí)橫屏轉(zhuǎn)豎屏左側(cè)多出大片空白;
當(dāng)設(shè)置masksToBounds = YES時(shí),如果文字長度超過了TextField的寬度,那么文字位置就會(huì)下移,如下圖:

當(dāng)設(shè)置masksToBounds = NO時(shí),如果文字長度超過了TextField的寬度且輸入速度過快,那么TextField左側(cè)會(huì)有文字閃動(dòng)的問題,且刪除文字時(shí)文字也會(huì)下移,如下圖:

當(dāng)文字長度超過了TextField的寬度由豎屏變?yōu)闄M屏?xí)r,那么TextField左側(cè)會(huì)有大片空白,如下圖:

原因分析
UITextField結(jié)構(gòu)如下圖,當(dāng)編輯時(shí)會(huì)成了UIFieldEditor,UIFieldEditor是繼承UIScrollView,UIFieldEditor有一個(gè)子視圖_UIFieldEditorContentView, _UIFieldEditorContentView用于展示文字和光標(biāo)(UITextSelectionView)。

當(dāng)編輯時(shí),_UIFieldEditorContentView的frame會(huì)動(dòng)態(tài)改變,UIFieldEditor的contentOffset也會(huì)改變,因此就出現(xiàn)了文字下移的問題。
解決方法
因此要防止文字下移,必須設(shè)置UIFieldEditor的contentOffset的y值為0,如果想解決第二張圖中輸入較快時(shí)左側(cè)閃動(dòng),則需設(shè)置masksToBounds = YES(使用者可自己設(shè)置)。
說明:即使設(shè)置了UIFieldEditor的contentOffset的y值為0,如果此時(shí)設(shè)置masksToBounds = YES,那么光標(biāo)下移問題依然存在,這是由于_UIFieldEditorContentView的frame的高度和y值改變導(dǎo)致的,因此需要?jiǎng)討B(tài)調(diào)整UIFieldEditor在y方向的偏移量。
為了解決前三張圖中問題,首先定義HHHTextField繼承自UITextField,在layoutSubviews中動(dòng)態(tài)進(jìn)行布局,代碼如下:
@interface HHHTextField()
{
CGFloat _defaultYOffset; //標(biāo)記_FieldEditorContentView初始偏y方向移量
}
@end
@implementation HHHTextField
- (void)layoutSubviews {
[super layoutSubviews];
for (UIScrollView *fieldEditor in self.subviews) {
if ([fieldEditor isKindOfClass:[UIScrollView class]]) { // UIFieldEditor
CGFloat currentYOffset = 0.0f;
for (UIView *fieldEditorContentView in fieldEditor.subviews) { //_FieldEditorContentView
currentYOffset = fieldEditorContentView.frame.origin.y;
if (_defaultYOffset == 0.0f && currentYOffset != 0.0f) {
_defaultYOffset = currentYOffset;
}
}
CGPoint offset = fieldEditor.contentOffset;
if (currentYOffset == 0.0f && _defaultYOffset != 0.0f) {
offset.y = -_defaultYOffset;
} else {
offset.y = 0.0f;
}
if (self.text.length == 0 && self.attributedText.length == 0) { //字體為空時(shí)重置_defaultYOffset
offset.y = 0.0f;
_defaultYOffset = 0.0f;
}
fieldEditor.contentOffset = offset;
break;
}
}
}
@end