屏幕旋转
认知
期望达到的目的
- 如何让App支持屏幕旋转
- 如何让App屏幕旋转
- 如何保证屏幕旋转后布局不会乱
总结
期望实现可主动旋转屏幕的操作方法
方法一
- 禁用旋转,
- shouldAutorotate
返回NO - 手动 transform / bounds / center 旋转视图
- 状态栏使用
UIApplication
的setStatusBarOrientation:animated
方法旋转
方法二
- 启用旋转,
- shouldAutorotate
返回YES(默认操作) - 使用条件限制 AppDelegate 中代理方法返回的界面方向
- 调用
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
修改界面方向 - 重写
- (BOOL)prefersStatusBarHidden
返回是否隐藏状态栏
总结内容来自下面所有超链接以及自身项目, 最下方保留一份博客文章
支持屏幕旋转
支持方式一
添加info.plist中Supported interface orientations
所包含的字段
以上图片代表同一种方式
支持方式二
在AppDelegate中实现程序级别的所支持界面方向的代理方法
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return UIInterfaceOrientationMaskXxx;
}
自定义旋转配置
控制器可以在内部管理自身所支持的旋转配置
自定义控制器旋转配置前提是已经使用以上方式设置支持屏幕旋转, 否则单独使用无效
- 是否自动旋转
- (BOOL)shouldAutorotate { return YES/NO; }
误区: shouldAutorotate并不单单代表自动旋转, 还相当于旋转的开关, 如果返回NO, 那么屏幕
- 所支持旋转方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations { return mask; }
旋转屏幕
自动感应旋转
条件
- 开启了屏幕旋转支持
- 没有使用
- shouldAutorotate
限制
手动旋转
id value = [NSNumber numberWithInteger: self.isFullScreen ? UIInterfaceOrientationLandscapeRight : UIInterfaceOrientationPortrait];
/// 核心代码
[[UIDevice currentDevice] setValue:value forKey:@"orientation"];
/// 等价于, 但是但是但是, 测试失败...失败啊
objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), self.isFullScreen?UIInterfaceOrientationLandscapeRight:UIInterfaceOrientationPortrait);
旋转后的布局
适当的位置布局
布局在 - viewWillLayoutSubviews
中进行, 发生旋转还会调用该方法
在内部判断当前屏幕的方向 / 宽高值进行不同的布局
旋转交互方法中更新布局
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// Code here will execute before the rotation begins.
// Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:].
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
// Place code here to perform animations during the rotation.
// You can pass nil for this closure if not necessary.
// Reorganize views, or move child view controllers.
if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
[self.redView mas_updateConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(200, 200));
}];
}
if (UIInterfaceOrientationIsPortrait([UIApplication sharedApplication].statusBarOrientation)) {
[self.redView mas_updateConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
}
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> context){
// Code here will execute after the rotation has finished.
// Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:].
// Do any cleanup, if necessary.
}];
}
注意:
在 iOS 9 以后,横屏时状态栏会隐藏,如果想要显示状态栏,需要手动控制。
- 在 Info.plist 中 设置 View controller-based status bar appearance 值为 YES
- 在 view controller 中重写 prefersStatusBarHidden 返回 false
override var prefersStatusBarHidden: Bool {
return false
}