zoukankan      html  css  js  c++  java
  • iOS8 Size Classes的理解与使用

    在iOS8中,新增了Size Classes特性,它是对当前所有iOS设备尺寸的一个抽象,也是该抽象了,想想现在多少种iOS尺寸的设备吧:iPhone4-5-6-6plus、iPad、iPad mini、iWatch,如何还是按照以前那针对种特定设备来编写不同的布局的话,一定是很糟糕的一件事情。

    现在有了sizeclass,事情就好办多了:你不是设备多吗,那我们就只把屏幕的宽和高分别分成三种情况:(Compact, Regular, Any),也即紧凑、正常和任意。这样宽和高三三一整合,一共9中情况。如下图所示,针对每一种情况,如果需要的话,我们可以单独在storyboard或xib中设置UIView的自动布局约束,甚至某一个button是否显示都是能轻松实现。

    和 UIKit 中的响应者链正好相反,traitCollection 将会在 view hierarchy 中自上而下地进行传递。对于没有指定 traitCollection 的 UI 部件,将使用其父节点的 traitCollection。这在布局包含 childViewController 的界面的时候会相当有用。在 UITraitEnvironment 这个接口中另一个非常有用的是 -traitCollectionDidChange:。在 traitCollection 发生变化时,这个方法将被调用。在实际操作时,我们往往会在 ViewController 中重写 -traitCollectionDidChange: 或者 -willTransitionToTraitCollection:withTransitionCoordinator: 方法 (对于 ViewController 来说的话,后者也许是更好的选择,因为提供了转场上下文方便进行动画;但是对于普通的 View 来说就只有前面一个方法了),然后在其中对当前的 traitCollection 进行判断,并进行重新布局以及动画。代码看起来大概会是这个样子:
    1. - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection  
    2.               withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator 
    3.     [super willTransitionToTraitCollection:newCollection  
    4.                  withTransitionCoordinator:coordinator]; 
    5.     [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) { 
    6.         if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) { 
    7.             //To Do: modify something for compact vertical size 
    8.         } else { 
    9.             //To Do: modify something for other vertical size 
    10.         } 
    11.         [self.view setNeedsLayout]; 
    12.     } completion:nil]; 
    在两个 To Do 中,我们应该删除或者添加或者更改不同条件下的 Auto Layout 约束 (当然,你也可以干其他任何你想做的事情),然后调用 -setNeedsLayout 来在上下文中触发转移动画。如果你坚持用代码来处理的话,可能需要面临对于不同 Size Classes 来做移除旧的约束和添加新的约束这样的事情,可以说是很麻烦 (至少我觉得是麻烦的要死)。但是如果我们使用 IB 的话,这些事情和代码都可以省掉,我们可以非常方便地在 IB 中指定各种 Size Classes 的约束 (稍后会介绍如何使用 IB 来对应 Size Classes)。另外使用 IB 不仅可以节约成百上千行的布局代码,更可以从新的 Xcode 和 IB 中得到很多设计时就可以实时监视,查看并且调试的特性。可以说手写 UI 和使用 IB 设计的时间消耗和成本差距被进一步拉大,并且出现了很多手写 UI 无法实现,但是 IB 可以不假思索地完成的任务。从这个意义上来说,新的 IB 和 Size Classes 系统可以说无情地给手写代码判了个死缓。
     
    另外,新的 API 和体系的引入也同时给很多我们熟悉的 UIViewController 的有关旋转的老朋友判了死刑,比如下面这些 API 都弃用了:
    1. @property(nonatomic, readonly) UIInterfaceOrientation interfaceOrientation 
    2.   
    3. - willRotateToInterfaceOrientation:duration: 
    4. - willAnimateRotationToInterfaceOrientation:duration: 
    5. - didRotateFromInterfaceOrientation: 
    6. - shouldAutomaticallyForwardRotationMethods 
    现在全部统一到了 viewWillTransitionToSize:withTransitionCoordinator:,旋转的概念不再被提倡使用。其实仔细想想,所谓旋转,不过就是一种 Size 的改变而已,我们都被 Apple 骗了好多年,不是么?
     

    在Xcode中的具体体现如下图:

    Alt text

    但是我们看到图中的宽度和高度都是Any,Any是什么意思呢?如果weight设为Anyheight设置为Regular,那么在该状态下的界面元素在只要heightRegular,无论weightRegular还是Compact的状态中都会存在。这种关系应该叫做继承关系,具体的四种界面描述与可继承的界面描述如下:

    • w:Compact h:Compact 继承 (w:Any h:Compact , w:Compact h:Any , w:Any h:Any)
    • w:Regular h:Compact 继承 (w:Any h:Compact , w:Regular h:Any , w:Any h:Any)
    • w:Compact h:Regular 继承 (w:Any h:Regular , w:Compact h:Any , w:Any h:Any)
    • w:Regular h:Regular 继承 (w:Any h:Regular , w:Regular h:Any , w:Any h:Any)

    我们知道了iOS 8下面设备界面可以描述为4种,但是这么多设备(iPhone4S,iPhone5/5s,iPhone6,iPhone6 Plus,iPad,Apple Watch)具体对应什么描述呢?经过查看官方文档和具体实践得知具体对应关系如下:

    • iPhone4S,iPhone5/5s,iPhone6
      • 竖屏:(w:Compact h:Regular)
      • 横屏:(w:Compact h:Compact)
    • iPhone6 Plus
      • 竖屏:(w:Compact h:Regular)
      • 横屏:(w:Regular h:Compact)
    • iPad
      • 竖屏:(w:Regular h:Regular)
      • 横屏:(w:Regular h:Regular)
    • Apple Watch(猜测)
      • 竖屏:(w:Compact h:Compact)
      • 横屏:(w:Compact h:Compact)

    Size Classes手写代码

    为了表征Size Classes,Apple在iOS8中引入了一个新的类,UITraitCollection。这个类封装了像水平和竖直方向的Size Class等信息。iOS8的UIKit中大多数UI的基础类(包括UIScreen,UIWindow,UIViewController和UIView)都实现了UITraitEnvironment这个接口,通过其中的traitCollection这个属性,我们可以拿到对应的UITraitCollection对象,从而得知当前的Size Class,并进一步确定界面的布局。和UIKit中的响应者链正好相反,traitCollection将会在view hierarchy中自上而下地进行传递。对于没有指定traitCollection的UI部件,将使用其父节点的traitCollection。这在布局包含childViewController的界面的时候会相当有用。在UITraitEnvironment这个接口中另一个非常有用的是-traitCollectionDidChange:。在traitCollection发生变化时,这个方法将被调用。在实际操作时,我们往往会在ViewController中重写-traitCollectionDidChange:或者-willTransitionToTraitCollection:withTransitionCoordinator:方法(对于ViewController来说的话,后者也许是更好的选择,因为提供了转场上下文方便进行动画;但是对于普通的View来说就只有前面一个方法了),然后在其中对当前的traitCollection进行判断,并进行重新布局以及动画。代码看起来大概会是这个样子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection 
                  withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
    {
        [super willTransitionToTraitCollection:newCollection 
                     withTransitionCoordinator:coordinator];
        [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) 
        {
            if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
                //To Do: modify something for compact vertical size
            } else {
                //To Do: modify something for other vertical size
            }
            [self.view setNeedsLayout];
        } completion:nil];
    }

    在两个To Do处,我们要手写代码针对不同的状态做调整。

    Size Classes与Interface Builder

    Xcode6中Interface BuilderSize Class有了很强大的支持,xib中可以开启Size Classes如下图:

    Alt text

    在不同的Size Classes描述下,界面元素可以选择安装还是不安装,具体操作如图:

    Alt text

    Size Classes与Image Asset

    Xcode6中Image Asset也支持了Size Class,也就是说,我们可以对不同的Size Class指定不同的图片了。在Image Asset的编辑面板中选择某张图片,Inspector里现在多了一个WidthHeight的组合,添加我们需要对应的Size Class,然后把合适的图拖上去,这样在运行时SDK就将从中挑选对应的Size的图进行替换了。支持Size ClassImage Asset编辑效果如下:

    Alt text

  • 相关阅读:
    浅读《构建之法》
    def 和 lamdba的区别
    Numpy和Pandas的区别
    Django:每点击一次就增加行可输入的表格
    F函数和Q函数的作用
    super()的用法
    liunx操作系统
    celery(超详细)
    celery
    FastDFS环境搭建
  • 原文地址:https://www.cnblogs.com/wfwenchao/p/4015333.html
Copyright © 2011-2022 走看看