最近使用 UITextField 的时候发现一个奇怪的问题,在一个普通的带有有导航栏的ViewController中,用普通的方式添加了一个普通的 UITextField,如图1(为了使问题更明显,所以把高度设成了300),输入文字之后,点按home键将程序切换到后台,然后再点击icon唤起程序时,textField中的内容会向下偏移一段距离,如图2。
黑人问号???
谷歌一下,我似乎发现了问题的原因:
原来,在iOS7后,苹果为 UIViewController 新添加了一个属性,而且其默认值为YES,
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets NS_AVAILABLE_IOS(7_0); // Defaults to YES
这个属性的作用是,指定控制器是否应该自动调整其子视图中 ScrollView 的 ContentInset,从而使其内容能够完整展示,不被status bar, search bar, navigation bar, toolbar 或者 tab bar遮盖。
最典型的例子就是iOS7后 UITableView 的 frame.origin.y 通常都是从0开始的,而当我们push到一个 tableViewController 时,其内容却不是从0开始,而是从64(导航栏+状态栏)开始的,就是这个属性起的作用,它会自动给tableView增加一个64的Top ContentInset(前提是当前页面有导航栏),这样得到的结果就是,tableView 是从界面顶部开始的,而其内容却是从导航栏下面开始的。
这个属性在一个界面有2个以上 tableView 的时候也会用上,与此属性类似的还有 edgesForExtendedLayout 和 extendedLayoutIncludesOpaqueBars ,具体的不同可以看苹果官方文档或者 戳这里。
然后,我设置当前VC的 automaticallyAdjustsScrollViewInsets = NO 之后,问题解决了。
但是,身为一个有梦想的程序员,我们不能止步于此。
这个属性是针对 UIScrollView 和它的子类的,但是 UITextFiled 可不是继承自 UIScrollView 啊 ?
于是,我推测应该是 UITextField 里面有一个子view是 UIScrollView 的子类,所以会受到 automaticallyAdjustsScrollViewInsets 属性的影响。
通过Xcode自带的 Debug View Hierarchy 工具查看内容偏移后的textFiled,如图3,发现 UITextFiled 有一个叫 UIFieldEditor 的子视图,它有一个 contentView,而它的bounds偏移了64,这不就是传说中的 UIScrollView 的子类嘛!
由于这个类是苹果的私有类,所以我们不能直接进入它的头文件查看,但是通过查阅资料发现,这个UIFieldEditor确实是UIScrollView的子类,如图4。
真相大白: )
另外,经同事提醒,只有在UITextField处于编辑状态时这个问题才会出现,用 Debug View Hierarchy 工具查看,发现UITextField在编辑状态时子视图是UIFieldEditor(UIScrollView的子类),而在非编辑状态时子视图是UITextFiledLabel(UILabel的子类), 斯国一 ~