iOS多设施适配简史以及相应的API支撑实现

作者 : 开心源码 本文共6362个字,预计阅读时间需要16分钟 发布时间: 2022-05-12 共204人阅读

远古的iPhone3和iPhone4时代,设施尺寸都是固定3.5inch,没有所谓的适配的问题,只要要用视图的frame属性进行硬编码就可。随着时间的推移,苹果的设施种类越来越多,尺寸也越来越大,单纯的frame已经不能简单处理问题了,于是推出了AutoLayout技术和SizeClasses技术来处理多种设施的适配问题。一直在做iOS开发的程序员相信在下面的两个版本交界处需要解决适配的坎肯定让你焦头烂额过:

  1. iOS7出来后视图控制器的根视图默认的尺寸是占据整个屏幕的,假如有半透明导航条的话也默认是延伸到导航栏和状态栏的下面。这段时间相信你对要同时满足iOS7和以下的版本进行大面积的改版和特殊适配解决,尤其是状态栏的高度问题尤为辣手。

  2. iOS11出来后尤其是iPhoneX设施推出,iPhoneX设施的特殊性体现为顶部的状态栏高度由20变为了44,底部还出现了一个34的安全区,当横屏时还需要考虑左右两边的44的缩进解决。你需要对所有的布局代码进行重新适配和梳理以便兼容iPhoneX和其余设施,这里面还是状态栏的高度以及底部安全区的的高度尤为辣手。

个人认为这两个版本的发布是iOS开发人员遇到的需要大量布局改版的版本。为了达到完美适配我们可能需要写大量的if,else以及写很多宏以及版本兼容来进行特殊解决。当然苹果也为上面两次大改版提供了诸多的处理方案:

  1. iOS7中对视图控制器提供了如下属性来处理版本兼容性的问题:
@property(nonatomic,assign) UIRectEdge edgesForExtendedLayout NS_AVAILABLE_IOS(7_0); // Defaults to UIRectEdgeAll@property(nonatomic,assign) BOOL extendedLayoutIncludesOpaqueBars NS_AVAILABLE_IOS(7_0); // Defaults to NO, but bars are translucent by default on 7_0.  @property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES@property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide API_DEPRECATED_WITH_REPLACEMENT("-[UIView safeAreaLayoutGuide]", ios(7.0,11.0), tvos(7.0,11.0));@property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide API_DEPRECATED_WITH_REPLACEMENT("-[UIView safeAreaLayoutGuide]", ios(7.0,11.0), tvos(7.0,11.0));
  1. iOS11中提出了一个安全区的概念,要求我们的可操作视图都放置在安全区内,并对视图和滚动视图提供了如下扩展属性:
@property (nonatomic,readonly) UIEdgeInsets safeAreaInsets API_AVAILABLE(ios(11.0),tvos(11.0));- (void)safeAreaInsetsDidChange API_AVAILABLE(ios(11.0),tvos(11.0));/* The top of the safeAreaLayoutGuide indicates the unobscured top edge of the view (e.g, not behind the status bar or navigation bar, if present). Similarly for the other edges. */@property(nonatomic,readonly,strong) UILayoutGuide *safeAreaLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));
/* When contentInsetAdjustmentBehavior allows, UIScrollView may incorporate its safeAreaInsets into the adjustedContentInset. */@property(nonatomic, readonly) UIEdgeInsets adjustedContentInset API_AVAILABLE(ios(11.0),tvos(11.0));/* Also see -scrollViewDidChangeAdjustedContentInset: in the UIScrollViewDelegate protocol. */- (void)adjustedContentInsetDidChange API_AVAILABLE(ios(11.0),tvos(11.0)) NS_REQUIRES_SUPER;/* Configure the behavior of adjustedContentInset. Default is UIScrollViewContentInsetAdjustmentAutomatic. */@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));/* contentLayoutGuide anchors (e.g., contentLayoutGuide.centerXAnchor, etc.) refer to the untranslated content area of the scroll view. */@property(nonatomic,readonly,strong) UILayoutGuide *contentLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));/* frameLayoutGuide anchors (e.g., frameLayoutGuide.centerXAnchor) refer to the untransformed frame of the scroll view. */@property(nonatomic,readonly,strong) UILayoutGuide *frameLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));

这些属性的具体意义这里就不多说了,网络上以及苹果的官方都有很多资料在详情这些属性的意思。从上面的这些属性中可以看出苹果提出的这些处理方案其主要是围绕处理视图和导航条、滚动视图、状态栏、屏幕边缘之间的关系而进行的。由于iOS7和iOS11两个版本中控制器中的视图和上面所列出的少量内容之间的关系变化最大。

NSLayoutConstraint束缚以及iOS9上的封装改进

在iOS6时代苹果推出了AutoLayout的技术处理方案,这是一套采用以相对束缚来替代硬编码的处理方法,然而糟糕的方法名和使用方式导致使用成本和代码量的急剧添加。比方下面的一段代码:

    UIButton *button = [self createDemoButton:NSLocalizedString(@"Pop layoutview at center", "") action:@selector(handleDemo1:)];    button.translatesAutoresizingMaskIntoConstraints = NO;  //button使用AutoLayout    [scrollView addSubview:button];    //下面的代码是iOS6以来自带的束缚布局写法,可以看出代码量较大。    [scrollView addConstraint:[NSLayoutConstraint  constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];        [scrollView addConstraint:[NSLayoutConstraint  constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1 constant:10]];        [scrollView addConstraint:[NSLayoutConstraint  constraintWithItem:button attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:40]];        [scrollView addConstraint:[NSLayoutConstraint  constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeWidth multiplier:1 constant:-20]];

一个简单的将按钮放到一个UIScrollView中去的代码,当用AutoLayout来实现时出现了代码量风暴问题。对于束缚的设置到了iOS9以后有了很大的改进,苹果对束缚的设置进行了封装,提供了三个类:NSLayoutXAxisAnchor, NSLayoutYAxisAnchor, NSLayoutDimension来简化束缚的设置,还是同样的功能用新的类来写束缚就简洁清晰很多了:

    UIButton *button = [self createDemoButton:NSLocalizedString(@"Pop layoutview at center", "") action:@selector(handleDemo1:)];    button.translatesAutoresizingMaskIntoConstraints = NO;  //button使用AutoLayout    [scrollView addSubview:button];    [button.centerXAnchor constraintEqualToAnchor:scrollView.centerXAnchor].active = YES;    [button.topAnchor constraintEqualToAnchor:scrollView.topAnchor constant:10].active = YES;    [button.heightAnchor constraintEqualToConstant:40].active = YES;    [button.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor multiplier:1 constant:-20].active = YES;
UIStackView

在iOS9中还提供了一个UIStackView的类来简化那些视图需要从上往下或者者从左往右依次增加排列的场景,通过UIStackView容器视图的使用就不再需要为每个子视图增加冗余的依赖束缚关系了。在大量的实践中很多应用的各模块其实都是按顺序从上到下排列或者者从左到右排列的。所以假如您的应用最低支持到iOS9的话即可以大量的应用这个类来构建你的程序了。

占位视图类UILayoutGuide

在iOS9以前两个视图之间的间距和间隔是无法支持浮动和可伸缩设置的,以及我们可以需要在两个视图之间保留一个浮动尺寸的空白区域,处理的方法是在它们中间加入一个透明颜色的UIView来进行解决,不论如何只需是View都需要进行渲染和绘制从而有可能肯定程度上影响程序的性能,而在iOS9以后提供了一个占位视图类UILayoutGuide,这个类就像是一个普通的视图一样可以为它设置束缚,也可以将它增加进入视图中去,也可以将这个占位视图作为其余视图的束缚依赖项,唯一的不同就是占位视图不会进行任何的渲染和绘制,它只会参加布局解决。因而这个类的引入可以很大程度上处理那些浮动间距的问题。

SizeClasses多屏幕适配

当我们的程序可能需要同时在横屏和竖屏下运行并且横屏和竖屏下的布局还不一致时,而且希望我们的应用在小屏幕上和大屏幕上(比方iPhone8 Plus 以及iPhoneX S Max)的布局有差异时,我们可能需要用到苹果的SizeClasses技术。这是苹果在iOS8中推出来的一个概念。 但是在实际的实践中我们很少有看到使用SizeClasses的例子和场景以及在我们开发中很少有使用到这方面的技术,所以我认为这应该是苹果的一个多屏幕适配的失败处理的方案。从字面了解SizeClasses就是尺寸的种类,苹果将设施的宽和高分为了压缩和常规两种尺寸类型,因而我们可以得到如下几种类型的设施:

设施方向类型
iPhone4/5/6/7/X竖屏w:Compact h:Regular
iPhone4/5/6/7/X横屏w:Compact h:Compact
iPhone6/7Plus, iPhoneXMax竖屏w:Compact h:Regular
iPhone6/7Plus, iPhoneXMax横屏w:Regular h:Compact
所有iPad竖屏w:Regular h: Regular
所有iPad横屏w:Regular h: Regular
所有iWatch竖屏w: Compact h: Compact
所有iWatch横屏w: Compact h: Compact

很欣慰的是假如您的应用是一个带有系统导航条的应用时很多适配的问题都能够得到很好的处理,由于系统已经为你做了很多事情,你不需要做任何特殊的解决。而假如你的应用的某个界面是present出来的,或者者是你自己实现的自己设置导航条的话,那么你可能就需要自己来解决各种版本的适配问题了。并且假如你的应用可能还有横竖屏的话那这个问题就更加复杂了。

最后除了可以用系统提供的API来处理所有的适配问题外,还向大家推荐我的开源布局库:MyLayout。它同时支持Objective-C以及Swift版本。而且用这个库后上面的所有适配问题都不是问题。


欢迎大家访问欧阳大哥2013的github地址和简书地址

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » iOS多设施适配简史以及相应的API支撑实现

发表回复