本文转载至 http://www.itjhwd.com/autolayout-uiview-uiviewcontroller-api/

细数AutoLayout以来UIView和UIViewController新增的相关API – UIViewController篇

UILayoutSupport

 
 
 
 
 

Java

 
1
2
3
4
5
6
@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这两个属性。像这样:

 
 
 
 
 

Java

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

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

并且使用这个属性布局时,在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

 
 
 
 
 

Java

 
1
- (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还另外提供了以下两个方法:

 
 
 
 
 

Java

 
1
2
- (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这样一组新的协议:

 
 
 
 
 

Java

 
1
2
3
4
5
6
7
- (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值改变时,对视图做对应的动画进行调整:

 
 
 
 
 

Java

 
1
2
3
4
5
6
7
8
9
10
11
12
- (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

 
 
 
 
 

Java

 
1
2
3
4
5
6
// 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中这些方法最终被调用的时机。

细数AutoLayout以来UIView和UIViewController新增的相关API的更多相关文章

  1. 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上)【转载】

    转自: DBAplus社群 http://www.toutiao.com/m5762164771/ 迄今最安全的MySQL?细数5.7那些惊艳与鸡肋的新特性(上) - 今日头条(TouTiao.com ...

  2. 细数iOS上的那些安全防护

    细数iOS上的那些安全防护  龙磊,黑雪,蒸米 @阿里巴巴移动安全 0x00 序 随着苹果对iOS系统多年的研发,iOS上的安全防护机制也是越来越多,越来越复杂.这对于刚接触iOS安全的研究人员来说非 ...

  3. 细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一

    细数.NET 中那些ORM框架 —— 谈谈这些天的收获之一(转) ADO.NET Entity Framework        ADO.NET Entity Framework 是微软以 ADO.N ...

  4. 细数Qt开发的各种坑(欢迎围观)

    1:Qt的版本多到你数都数不清,多到你开始怀疑人生.从4.6开始到5.8,从MSVC编译器到MINGW编译器,从32位到64位,从Windows到Linux到MAC.MSVC版本还必须安装对应的VS2 ...

  5. 细数Python Flask微信公众号开发中遇到的那些坑

    最近两三个月的时间,断断续续边学边做完成了一个微信公众号页面的开发工作.这是一个快递系统,主要功能有用户管理.寄收件地址管理.用户下单,订单管理,订单查询及一些宣传页面等.本文主要细数下开发过程中遇到 ...

  6. 细数MQ那些不得不说的8大好处

    消息队列(MQ)是目前系统架构中主流方式,在大型系统及大数据中广泛采用.对任何架构或应用来说, MQ都是一个至关重要的组件.今天我们就来细数MQ那些不得不说的好处. 好处一:解耦 在项目启动之初来预测 ...

  7. 细数 Windows Phone 灭亡的七宗罪(过程很详细,评论很精彩,但主要还是因为太慢了,生态跟不上,太贪了,厂商不愿意推广)

    曾梦想仗剑走天涯,看一看世界的繁华 年少的心有些轻狂,如今你四海为家 曾让你心疼的姑娘,如今已悄然无踪影 犹记得上大学攒钱买了第一台智能手机Lumia 520时,下载的第一首歌曲<曾经的你> ...

  8. 细数Intellij Idea10个蛋疼问题!

    Intellij Idea以下简称IJ. 昨天细数了IJ上的10大666的姿势,IJ确实很智能,在很多方便可以完爆Eclipes,可在某些方面真的被Eclipse秒杀 1.乱码 在Eclipse中很少 ...

  9. iOS UIViewController 和 nib 相关的3个方法

    iOS UIViewController 的 awakeFromNib 以及 - (id)initWithCoder:(NSCoder *)aDecoder 和 - (instancetype)ini ...

随机推荐

  1. [uiautomator篇]uiwatcher 的使用场景

    http://www.yangyanxing.com/article/use-watcher-in-uiautomator.html   今天在uiautomator中实践了watcher的用法,这个 ...

  2. 【Luogu】P1040加分二叉树(区间DP)

    题目链接 区间DP,因为中序遍历的性质:区间[l,r]的任何一个数都可以是该区间的根节点. 更新权值的时候记录区间的根节点,最后DFS输出. 见代码. #include<cstdio> # ...

  3. BZOJ [HNOI2015]亚瑟王 ——期望DP

    发现每张卡牌最后起到作用只和是否打出去了有关. 而且每张牌打出去的概率和之前的牌打出去的情况有关. 所以我们按照牌的顺序进行DP. 然后记录$i$张牌中打出$j$张的概率,然后顺便统计答案. 直接对系 ...

  4. ci框架——辅助函数

    辅助函数:application/helper下面.命名要求为***_helper.php;这样在调用的时候直接$this->load->helper('***');若想给自定义的辅助函数 ...

  5. CF 2018 Battle of Brains GYM 102062 F

    https://codeforces.com/gym/102062/attachments/download/8213/2018-battle-of-brains-en.pdf https://cod ...

  6. android调用 .net webService

    package com.rockcheck.mes; import android.os.AsyncTask; import android.support.v7.app.AppCompatActiv ...

  7. T3139 栈练习3 codevs

    http://codevs.cn/problem/3139/ 题目描述 Description 比起第一题,本题加了另外一个操作,访问栈顶元素(编号3,保证访问栈顶元素时或出栈时栈不为空),现在给出这 ...

  8. NOIP临考经验(转)

    [COGS]NOIP临考经验 1.  提前15分钟入场,此时静坐调整心态,适当的深呼吸 2.  打开编辑器并调整为自己喜欢的界面 3.  熟悉文件目录,写好准确无误的代码模板 4.  压缩包或许还不能 ...

  9. 洛谷 P2831 愤怒的小鸟

    P2831 愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0)(0,0) 处,每次 Kiana 可以用它向第一象 ...

  10. 2.JAVA语言基础部分

    1.语言基础 二进制操作 "&"按位与:a与b同时为1结果为1,否则为0: "|"按位或:a与b其中任一个为1,否则为0 "~"按位 ...