为何UIViewController的视图旋转时能自动调整frame,普通UIView却不行?
一、普通UIView设置frame后不随旋转调整的原因
直接通过代码创建的UIView,默认的autoresizingMask是UIViewAutoresizingNone,也就是没有任何自动调整尺寸的规则。当你给它设置frame并添加到父视图后,屏幕旋转导致父视图尺寸变化时,系统不会自动修改这个子视图的frame——因为没有规则告诉它该怎么调整。如果想要它跟随父视图尺寸变化,你需要手动设置autoresizingMask(比如.flexibleWidth | .flexibleHeight),或者添加Auto Layout约束。
对应的代码示例:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let subview = UIView() subview.backgroundColor = .red subview.frame = view.frame // 开启自动调整,让子视图跟随父视图宽高变化 subview.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(subview) } }
二、UIViewController的view自动随旋转调整的原因
UIViewController的view本质上还是UIView,但它被ViewController本身接管了布局管理:
- 系统默认给ViewController的view设置了
autoresizingMask = [.flexibleWidth, .flexibleHeight],确保它能跟随父容器的尺寸变化; - ViewController会监听
traitCollection的变化(比如屏幕旋转触发的尺寸类变化),在traitCollectionDidChange方法中自动更新view的布局,保证它始终填满自己的容器(比如导航控制器、tabBar控制器的容器,或者你添加它的父视图)。
即使你手动设置了它的frame,ViewController在生命周期和trait变化时,依然会根据自身的容器尺寸重新调整view的frame,所以旋转时它会自动适配新的屏幕尺寸。
三、是否所有场景都必须用Auto Layout约束?
不是的。苹果文档推荐在自定义模态转场、导航推送转场中使用frame,是因为这类场景的核心是动态动画效果——转场过程中视图的位置、尺寸需要实时变化,用frame可以直接、高效地控制每一步的位置,而Auto Layout约束在动画时需要修改constant、激活/禁用约束,操作相对繁琐,性能也不如直接修改frame灵活。
但在静态布局场景(比如视图添加后需要适配不同屏幕尺寸、支持旋转),Auto Layout约束(或autoresizingMask)是更优的选择,它们能自动处理尺寸变化,不需要你手动修改frame。
总结来说:
- 动画、转场这类动态控制场景,优先用
frame; - 静态布局、适配不同尺寸/旋转的场景,优先用约束或
autoresizingMask。
内容的提问来源于stack exchange,提问作者Crocobag

