文章目录

  • iOS关于屏幕适配
  • 基础
  • 大小屏
  • 横竖屏切换
  • 特殊机型
  • 注意


iOS关于屏幕适配

基础

  • 有两个重要的关乎适配的方法:

- (void)layoutSubviews- (void)viewDidLayoutSubviews

-layoutSubviews是UIView的方法。当view需要布局或重新布局的时候就会调用这个方法。例如,tableView刷新的时候,cell会重新布局,layoutSubviews就会执行;当view上添加或者移除一个子空间时,view会重新布局,这个方法也会被调用;还有当我们手动调用UIView的-layoutIfNeed方法时,通知view重新布局,-layoutSubviews也会被调用。所以UIView子空间的布局在这个方法里处理是可以的。

-layoutSubviews是UIViewController的方法,当controller的self.view需要布局或者重新布局的时候就会执行。例如,横竖屏切换的时候这个方法就会被调用。self.view上的控件在这个方法里处理。

  • Autoresizing

另外UIView有个属性Autoresizing,也与屏幕适配有些关系。

大小屏

大小屏字体、控件大小…

横竖屏切换

有些空间可能横竖屏显示效果是类似的,只是大小变化,这时候只需要在-layoutSubviews方法里直接处理。

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    self.titleLabel.frame = CGRectMake(0, CGRectGetHeight(self.bounds)*0.5-36*0.5, CGRectGetWidth(self.bounds),36);
}

在UI设计上,有些控件横竖屏显示不一样,横屏是一个位置,竖屏在另外一个位置,这样的可通过statusBarOrientation的变化可以定位到屏幕选择的方向。

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
    if (currentOrientation == UIInterfaceOrientationLandscapeLeft || currentOrientation == UIInterfaceOrientationLandscapeRight) {
        [self setOrientationLandscapeConstraint];
    } else {
        [self setOrientationPortraitConstraint];
    }
}
- (void)setOrientationPortraitConstraint
{
}
- (void)setOrientationLandscapeConstraint
{   
}

在基类的View的-layoutSubviews和基类的ViewController的-viewDidLayoutSubviews方法里面,通过检测statusBarOrientation的方向来确定当前是需要适配横屏还是竖屏,从而进行子控件的布局。

iOS13,statusBarOrientation属性被废弃使用了,改用windowScene.interfaceOrientation。但是需要注意的是Xcode11之后新建的项目里UIApplication.sharedApplication.delegate,即Appdelegate里没有Window这个属性,需要添加一个window属性,并在SceneDelegate里给赋值,不然UIApplication.sharedApplication.delegate会闪退。

UIInterfaceOrientation currentOrientation = UIInterfaceOrientationUnknown;
    if (@available(iOS 13.0, *)) {
        currentOrientation = UIApplication.sharedApplication.delegate.window.windowScene.interfaceOrientation;
    } else {
        currentOrientation = UIApplication.sharedApplication.statusBarOrientation;
    }
    if (currentOrientation == UIInterfaceOrientationLandscapeLeft || currentOrientation == UIInterfaceOrientationLandscapeRight) {
        [self setOrientationLandscapeConstraint];
    } else {
        [self setOrientationPortraitConstraint];
    }

特殊机型

iPhoneX这种有刘海的和以前的iPhone6适配可能会有些差别,而且导航栏大小等会发生了变化,像这种适配我觉得从创建项目初就应该考虑到这种刘海适配的问题。

单独的页面对刘海进行适配,会用到一些相关的宏,这样可能会比较麻烦。

自定义基类ViewController的view是一个可以尝试的方案。

注意

当设置UILabel/UITextField的translatesAutoresizingMaskIntoConstraints属性设置为NO时,每次给label赋值都会调用手动布局的方法-layoutSubviews/-viewDidLayoutSubviews,这时候刷新布局会很频繁。尽量不要这么做。