• AutoLayout以来UIView和UIViewController新增的相关API


     

    http://www.itjhwd.com/autolayout-uiview-uiviewcontroller-api/

    @property(nonatomic,readonly,retain) id<UILayoutSupport> topLayoutGuide NS_AVAILABLE_IOS(7_0);  
    @property(nonatomic,readonly,retain) id<UILayoutSupport> bottomLayoutGuide NS_AVAILABLE_IOS(7_0);  
    @protocol UILayoutSupport <NSObject>  
    @property(nonatomic,readonly) CGFloat length;  
    @end 

    从iOS 7以来,当我们的视图控制器结构中有NavigationBar,TabBar或者ToolBar的时候,它们的translucent属性的默认值改为 了YES,并且当前的ViewController的高度会是整个屏幕的高度。(比如一个场景:拖动TableView的时候,上面的 NavigationBar能够透过去看到TableView的内容。)

    为了确保我们的视图不被这些Bar覆盖,我们可以在我们AutoLayout布局中使用topLayoutGuide和bottomLayoutGuide这两个属性。像这样:

    NSDictionary *views = @{"topLayoutGuide" : self.topLayoutGuide, @"myLabel" : myLabel};  
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topLayoutGuide]-[myView]" options:0 metrics:nil views:views] 

    这个时候我们的视图就不会被Bar所覆盖,显示在了Bar下方:

    细数AutoLayout以来UIView和UIViewController新增的相关API - 第1张  | IT江湖

    并且使用这个属性布局时,在traitCollection改变时(旋转屏幕),它的值也会动态变化。上述代码,在横屏情况下,navigationbar高度变了之后,仍然能够正确显示。

    这两个guides的计算方式如下:

    topLayoutGuide是通过计算 View Controller->View->Top 到 覆盖这个View最下层的那个Bar(像Navigation Bar) -> Bottom 的距离
    bottomLayoutGuide是通过计算 View Controller->View->Bottom 到 覆盖这个View上层那个Bar(像Tab bar) -> Top 的距离


    如果我们不使用AutoLayout布局,我们也可以通过Guide的length属性获得相应的距离。我们应该在-viewDidLayoutSubviews或者-layoutSubviews调用super之后,再去获得length这个值,以确保正确。

    UIConstraintBasedLayoutCoreMethods

    - (void)updateViewConstraints NS_AVAILABLE_IOS(6_0); 

    UIViewController中也新增了一个更新布局约束的方法,在AutoLayout UIView相关API的笔记中,详细讲述了UIView的一组更新布局约束的方法。

    这个方法默认的实现是调用对应View的 -updateConstraints 。ViewController的View在更新视图布局时,会先调用ViewController的updateViewConstraints 方法。我们可以通过重写这个方法去更新当前View的内部布局,而不用再继承这个View去重写-updateConstraints方法。我们在重写这 个方法时,务必要调用 super 或者 调用当前View的 -updateConstraints 方法。

    UITraitEnvironment

    又一次看到了UITraitEnvironment协议,在UIKit Framework中,有四个类支持这个协议,分别是UIScreen, UIViewController,UIView 和 UIPresentationController。所以当视图的traitCollection改变时,UIViewController能够捕获到这 个消息,并做对应处理的。 更多解释可以参考上一篇文章详解UICoordinateSpace和UIScreen在iOS 8上的坐标问题。

    关于Size Class和UITraitCollection的概念可参考如下链接:

    WWDC 2014 Session笔记 – iOS界面开发的大一统 From: onecat’s Blog

    iOS8 Size Classes的理解与使用 From: Joywii’s Blog 

    另外,UIViewController还另外提供了以下两个方法:

    - (void)setOverrideTraitCollection:(UITraitCollection *)collection forChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0);  
    - (UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0); 

    我们可以通过调用ViewController的setOverrideTraitCollection方法为它的 ChildViewController重新设置traitCollection的值。一般情况下traitCollection值从父 controller传到子controller是不做修改的。当我们自己实现一个容器Controller的时候,我们可以使用这个方法进行调整。

    相对的,我们可以通过overrideTraitCollectionForChildViewController方法获得ChildViewController的traitCollection值。

    UIContentContainer

    iOS 8上随着Size Class概念的提出,UIViewController支持了UIContentContainer这样一组新的协议:

    - (void)systemLayoutFittingSizeDidChangeForChildContentContainer:(id <UIContentContainer>)container NS_AVAILABLE_IOS(8_0);  
    - (CGSize)sizeForChildContentContainer:(id <UIContentContainer>)container withParentContainerSize:(CGSize)parentSize NS_AVAILABLE_IOS(8_0);  
    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0);  
    - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0); 

    UIViewController对这组协议提供了默认的实现。我们自定义ViewController的时候可以重写这些方法来调整视图布局,比如我们 可以在这些方法里调整ChildViewControler的位置。当我们重写这些协议方法时,我们通常都去调用 super。

    viewWillTransitionToSize: ViewController的View的size被他的Parent Controller改变时,会触发这个方法。(比如rootViewController在它的window旋转的时候)。我们在重写这个方法时,确保 要调用super,来保证size改变的这条消息能够正常传递给它的Views或者ChildViewControllers。

    willTransitionToTraitCollection: 当ViewController的traitCollection的值将要改变时会调用这个方法。这个方法是在 UITraitEnvironment协议方法 traitCollectionDidChange:之前被调用。我们在重写这个方法时,也要确保要调用super来保证消息的传递。比如,我们可以像这 样在traitCollection值改变时,对视图做对应的动画进行调整:

    - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection  
              withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator  
    {  
        [super willTransitionToTraitCollection:newCollection  
                 withTransitionCoordinator:coordinator];  
        [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {  
        if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {  
        } else {  
        }  
        [self.view setNeedsLayout];  
        } completion:nil];  
    } 

    sizeForChildContentContainer:一个容器ViewController可以使用这个方法设置 ChildViewController的size。当容器 ViewControllerviewWillTransitionToSize:withTransitionCoordinator:被调用时(我们 重写这个方法时要调用Super),sizeForChildContentContainer方法将会被调用。然后我们可以把需要设置的size发送给 ChildViewController。当我们设置的这个size和当前ChildViewController的size一样,那么 ChildViewController的viewWillTransitionToSize方法将不会被调用。

    sizeForChildContentContainer默认的实现是返回 parentSize。

    systemLayoutFittingSizeDidChangeForChildContentContainer:当满足如下情况,这个方法会被调用:

    当前ViewController没有使用AutoLayout布局
    ChildrenViewController的View使用了AutoLayout布局
    ChildrenViewController View -systemLayoutSizeFittingSize:方法返回的值改变(View由于内容的变化,size也出现了变化)

    preferredContentSize

    // From UIContentContainer Protocol  
    @property (nonatomic, readonly) CGSize preferredContentSize NS_AVAILABLE_IOS(8_0);  
    - (void)preferredContentSizeDidChangeForChildContentContainer:(id <UIContentContainer>)container NS_AVAILABLE_IOS(8_0);  
    // From UIViewController  
    @property (nonatomic) CGSize preferredContentSize NS_AVAILABLE_IOS(7_0); 

    preferredContentSize在UIContentContainer协议中是只读的,对应的UIViewController有可写的版 本。我们可以使用preferredContentSize来设置我们期望的ChildViewController的界面大小。举个例子,如果应用中使 用的popOver大小会发生变化,iOS7之前我们可以用contentSizeForViewInPopover来调整。iOS7开始这个API被废 弃,我们可以使用preferredContentSize来设置。

    当一个容器ViewController的ChildViewController的这个值改变时,UIKit会调用 preferredContentSizeDidChangeForChildContentContainer这个方法告诉当前容器 ViewController。我们可以在这个方法里根据新的Size对界面进行调整。

    总结
    UIViewController到目前为止(iOS 8.1), 关于布局的API最大的变化是iOS8中新增支持的两组协议:UITraitEnvironment 和 UIContentContainer。我们可以在学习中通过Demo实现这些协议,来观察ViewController中这些方法最终被调用的时机。

  • 相关阅读:
    《舌尖上的中国》精彩故事
    5年前的笔试题目
    遍历物理模型中的所有表,将表名、表代码、字段名、字段代码全部由小写改成大写
    MongoDB下载文件 百度盘共享
    认识MEAN开发框架[转]
    智能油田
    排课相关参数设置
    spring获取所有被装配类工具
    oracle常用sql集锦
    关于使用easyUI遇到过的一些坑
  • 原文地址:https://www.cnblogs.com/allanliu/p/4544586.html
Copyright © 2020-2023  润新知