文档章节

哪里写Autolayout布局最合适?

hejunbinlan
 hejunbinlan
发布于 2016/07/29 13:29
字数 1894
阅读 28
收藏 0
点赞 0
评论 0

用户需求一览

申请者fengmingxiao

项目大致代码行数500

项目 GitHub 地址

项目备注

探究UI布局方面的代码应该怎么写才是规范的,希望您能够 看看Readme,万分感谢,这不是什么大工程,但是我目前最棘手的问题

在哪里写Autolayout布局最合适?

在回答这个问题前,我们先看一看UIView这个类的头文件里有哪些和布局相关的方法.

// Allows you to perform layout before the drawing cycle happens. -layoutIfNeeded forces layout early
    public func setNeedsLayout()
    public func layoutIfNeeded()

    public func layoutSubviews()

相信如果从纯frame布局时代过来的人应该对这三个方法比较熟悉.
说一个场景.如图,我创建了一个自定义的黑色View,里面包含一个红色的view,一个黄色的view.
Button的事件,是将黑色View的宽高都扩大一倍.
我点击完Button之后.效果如下.

你们会发现,黄色视图的宽高发生了变化,而红色的没有.为什么呢?
因为我在创建黑色视图的时候重写了layoutSubviews()方法.

override func layoutSubviews() {
        yellowView.frame = CGRectInset(self.bounds, 20, 20)
    }

也就是说,layoutSubViews总是会在父Viewframe发生变化的时候触发.(不止这一个场景会被触发.)
列举一下. layoutSubviews在以下情况下会被调用: 1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。
所以如果子view的宽高与父view的宽高相关的话,就需要这样写.当然,这是远古时代的写法了.现在我们如果使用Autolayout的话,就不需要关心这些了.
那么我最上面贴的三个方法中的前两个是干吗的呢?
解释如下.
setNeedsLayout()方法: 标记为需要重新布局,异步调用layoutIfNeeded()刷新布局,不立即刷新,但layoutSubviews()一定会被调用 layoutIfNeeded()方法:如果,有需要刷新的标记,立即调用layoutSubviews()进行布局(如果没有标记,不会调用layoutSubviews()

如果要立即刷新,要先调用view.setNeedsLayout(),把标记设为需要布局,然后马上调用view.layoutIfNeeded(),实现布局

在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用view.layoutIfNeeded()

好的讲完了frame布局.下面来讲一下现在最常使用的Autolayout布局.

Autolayout

在UIView的头文件中,Autolayout相关的方法一般有下面几个.

 public func updateConstraintsIfNeeded() // Updates the constraints from the bottom up for the view hierarchy rooted at the receiver. UIWindow's implementation creates a layout engine if necessary first.
    @available(iOS 6.0, *)
    public func updateConstraints() // Override this to adjust your special constraints during a constraints update pass
    @available(iOS 6.0, *)
    public func needsUpdateConstraints() -> Bool
    @available(iOS 6.0, *)
    public func setNeedsUpdateConstraints()
}

其实关于这几个方法的解释,苹果官方文档已经解释的很清楚了.

needsUpdateConstraints() -> Bool这个方法返回一个Bool值,来决定一个view是否会执行updateConstraints()这个方法.

updateConstraints()方法一般会重写,用来更新特定的constraint(这个方法使用较复杂,下面细讲).

updateConstraintsIfNeeded()方法和setNeedsUpdateConstraints()方法的含义和上述的public func setNeedsLayout()public func layoutIfNeeded()类似.只不过一个是针对frame布局更新.,一个是针对Autolayout的布局更新. setNeedsUpdateConstraints()方法会在每次view中布局发生变化的时候都会触发,提醒view应当更新了.相当于是设置一个标记.这个方法调用的时候,布局变化并不会立刻生效,只是提醒系统.
updateConstraintsIfNeeded()这个方法调用的时候,会立刻强制刷新被标记为需要刷新的布局.

为什么说updateConstraints()使用起来特别纠结?

解释如下.

Custom views that set up constraints themselves should do so by overriding this method. When your custom view notes that a change has been made to the view that invalidates one of its constraints, it should immediately remove that constraint, and then call setNeedsUpdateConstraints to note that constraints need to be updated. Before layout is performed, your implementation of updateConstraints will be invoked, allowing you to verify that all necessary constraints for your content are in place at a time when your custom view’s properties are not changing.

这是苹果官网给出的解释.
意思是:当视图的改变使得某个约束无效时,应当把该约束移除,并调用 setNeedsUpdateConstraints 以标记视图需要更新约束,然后在 updateConstraints 中更新约束。

但是实际上使用起来几乎等同于扯淡.

why?
每次执行 updateConstraints() 方法时,视图的状态并不是完全相同的。视图可能已经有一些约束了,而且大部分情况下你可能只想更改一部分约束。这就导致 updateConstraints() 中散落着各种if语句用来判断指定的约束是否已经存在。 视图也不一定完全拥有它的所有约束。视图层级中的其他视图可能会把约束加到你的视图上,所以你的代码也不能假设constraints数组中的哪个约束是干什么的。这意味着你必须用单独的属性来跟踪所有可能需要修改的约束。 改变约束通常是在响应事件的时候。如果你遵循了官方文档的建议,在处理事件,改变内部状态后,就需要调用 setNeedsUpdateConstraints() 。 结果就是:修改布局的代码(在updateConstraints() 里面)和触发修改的代码分离在不同的地方,逻辑难以理解。

##说了那么多,到底应该怎么做?
在今年的WWDC技术讲座 Mysteries of Auto Layout (Part 2) 上,苹果给出了不同的建议:

Really, all this is is a way for views to have a chance to make changes to constraints just in time for the next layout pass, but it’s often not actually needed.
All of your initial constraint setup should ideally happen inside Interface Builder. Or if you really find that you need to allocate your constraints programmatically, some place like viewDidLoad is much better. updateConstraints is really just for work that needs to be repeated periodically.
Also, it’s pretty straightforward to just change constraints when you find the need to do that; whereas, if you take that logic apart from the other code that’s related to it and you move it into a separate method that gets executed at a later time, your code becomes a lot harder to follow, so it will be harder for you to maintain, it will be a lot harder for other people to understand.
So when would you need to use updateConstraints? Well, it boils down to performance. If you find that just changing your constraints in place is too slow, then update constraints might be able to help you out. It turns out that changing a constraint inside updateConstraints is actually faster than changing a constraint at other times. The reason for that is because the engine is able to treat all the constraint changes that happen in this pass as a batch.

简单来说.不要将 updateConstraints() 用于视图的初始化设置。当你需要在单个布局流程(single layout pass)中添加、修改或删除大量约束的时候,用它来获得最佳性能。如果没有性能问题,直接更新约束更简单。

最后一句话总结.
在哪里创建autolayout.
View中:直接在init方法里创建.
ViewController中:直接在viewDidLoad()里创建.
有人问,如果用IB创建约束,在viewDidLoad里不能获取到某个view的正确frame,怎么办?
这个时候你需要在一个叫viewDidLayoutSubviews()里的方法里获取一个view的正确frame.

参考文章

  1. 產生 Auto Layout Constraints 的程式碼要放在哪裡
  2. What is the difference between all these Auto Layout update methods? Are all necessary?
  3. Objective-C setNeedsUpdateConstraints vs. updateConstraintsIfNeeded

© 著作权归作者所有

共有 人打赏支持
hejunbinlan
粉丝 40
博文 532
码字总数 21018
作品 0
浦东
高级程序员
从此爱上iOS Autolayout

这篇不是autolayout教程,只是autolayout动员文章和经验之谈,在本文第五节友情链接和推荐中,我将附上足够大家熟练使用autolayout的教程。这篇文章两个月前就想写下来,但因为一直工作较多,...

hejunbinlan ⋅ 2016/08/01 ⋅ 0

IOS --Xcode6 自动布局

一、自动布局(autolayout) 一款ios app最主要的UI组件是由一个个相对独立的可视化单元组成,例如view、label、button等。这些可视化单元的关系由两个基本关系构成:兄弟关系和父子关系。 对于...

求是科技 ⋅ 2015/03/12 ⋅ 0

tableHeaderView的autolayout

新项目开始了,准备用上强大的,说到这里感觉很惭愧,直到现在才开始用,我一直是手写代码,所以首选Masonry来写autolayout的代码。网上的教程还是挺多的,最实在的还是看Masonry中demo,里面...

hejunbinlan ⋅ 2016/08/04 ⋅ 0

使用aulayout自适应uitableviewcell高度

在使用autolayout的项目中,单元格的自适应高度,可能有点复杂,特别是对于复杂一点的自定义单元格;那么下面就这个autolayout自适应单元格,通过代码来说明: -(CGFloat)tableView:(UITable...

HillYoung ⋅ 2016/01/19 ⋅ 0

Auto Layout + Manual Layout 混用

约束代码混用的问题 无数人趟过此坑,大部分人在坑中一蹶不振,小部分人爬起来也是跌跌撞撞。 有很多人都说auto layout和manual layout的坐标设置是不能混用的,会导致出现布局问题。首先声明...

人独立 ⋅ 2015/12/04 ⋅ 0

Autolayout优秀的第三方开源库

今天才发现CSDN支持markdown了…还是给出新博客地址:Autolayout优秀的第三方开源库 最近项目开始用纯代码布局整个UI框架, 对于前一段很长时间都是xib+storyboard狂拖控件约束的我来说,每天写...

humingtao2013 ⋅ 2015/06/25 ⋅ 0

Autolayout使用小结(一)

Autolayout使用小结(一) 最近做项目时,因为iPhone6和iPhone6Plus的兼容,我们启用了Autolayout. 以前是因为不用也能满足需求,也是因为懒,没有认真使用,只是了解过。经过一段时间的使用...

法斗斗 ⋅ 2015/10/14 ⋅ 0

AutoLayout(III):浅析动画

前面讲过了AutoLayout的基本概念和遇到的一些问题,这篇讲的是AutoLayout下的动画。自动布局已经比传统的Frame复杂,动画也会稍微更复杂些。期望通过这篇文章,能够对AutoLayout下的动画有理...

hejunbinlan ⋅ 2016/07/29 ⋅ 0

Autolayout小结(二)

Autolayout小结(二) 在Autolayout小结(一)中介绍了在Autolayout学习中一些基本的注意点,本文会针对一些布局上常见的问题进行分析。 如何自动适应cell的高度 如何在ScrollView中使用Autol...

法斗斗 ⋅ 2015/10/14 ⋅ 0

Xcode6中自动布局autolayout和sizeclass的使用

一、关于自动布局(Autolayout) 在Xcode中,自动布局看似是一个很复杂的系统,在真正使用它之前,我也是这么认为的,不过事实并非如此。 我们知道,一款iOS应用,其主要UI组件是由一个个相对...

泊竹 ⋅ 2014/09/20 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 31分钟前 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 36分钟前 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

马氏距离与欧氏距离

马氏距离 马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度。 如果协方差矩阵为单位矩阵,那么马氏距离就简化为欧氏距离,如果协方差矩阵为对角阵,则其也...

漫步当下 ⋅ 昨天 ⋅ 0

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 昨天 ⋅ 0

Spring clound 组件

Spring Cloud技术应用从场景上可以分为两大类:润物无声类和独挑大梁类。 润物无声,融合在每个微服务中、依赖其它组件并为其提供服务。 Ribbon,客户端负载均衡,特性有区域亲和、重试机制。...

英雄有梦没死就别停 ⋅ 昨天 ⋅ 0

Confluence 6 重新获得站点备份文件

Confluence 将会创建备份,同时压缩 XML 文件后存储熬你的 <home-directory>/backups> 目录中。你需要自己访问你安装的 Confluence 服务器,并且从服务器上获得这个文件。 运行从 Confluence...

honeymose ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部