问题
新项目中自定义tabbar,重新设置了UITabbarButton的frame,当在控制器中对title赋值时,奇迹出现:tabbar的按钮位置会左右交换。
思考
位置的改变源于自定义tabbar,问题代码
override func layoutSubviews() {
...
for barButton in subviews
...
}
再看看subviews的定义
The receiver’s immediate subviews.
You can use this property to retrieve the subviews associated with your custom view hierarchies. The order of the subviews in the array reflects their visible order on the screen, with the view at index 0 being the back-most view.
For complex views declared in UIKit and other system frameworks, any subviews of the view are generally considered private and subject to change at any time. Therefore, you should not attempt to retrieve or modify subviews for these types of system-supplied views. If you do, your code may break during a future system update.
subviews的顺序取决于它们在屏幕上的可见顺序,索引0的在最后,并且顺序随时可能改变。
什么操作导致的?
当设置控制器的title时,会产生bug。
再看看title的定义
A localized string that represents the view this controller manages.
Set the title to a human-readable string that describes the view. If the view controller has a valid navigation item or tab-bar item, assigning a value to this property updates the title text of those objects.
表示控制器管理的视图的字符串。如果控制器有一个有效的navigationItem或者tabbarItem,将会更新这些对象属性的title。
也就是会对navigationItem.title和tabBarItem.title赋值,从而引起subviews视图顺序产生变化。然后系统会调用layoutSubviews。
这时候subviews顺序已经改变,再次布局就会导致按钮位置的错误。
验证
符号断点subviews和layoutSubviews,查看调用栈
UIViewController设置title后,调用了subviews,然后调用layoutSubviews。
解决
最终还是顺序的问题,那就以改变前的子视图的x值对subviews进行排序。
排序后再去布局,相对于原来UITabbarButton的顺序不变,也就不会产生左右交换。
let sortedSubviews = subviews.sorted { (view0, view1) -> Bool in
return view0.xValue < view1.xValue
}
for barButton in sortedSubviews
其他
self.navigationItem.title //sets navigation bar title.
self.tabBarItem.title // sets tab bar title.
self.title // sets both of these.