文档章节

哪里写Autolayout布局最合适?

hejunbinlan
 hejunbinlan
发布于 2016/07/29 13:29
字数 1894
阅读 91
收藏 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

本文转载自:http://reviewcode.cn/article.html?reviewId=14

共有 人打赏支持
hejunbinlan
粉丝 41
博文 595
码字总数 21569
作品 0
浦东
高级程序员
私信 提问
从此爱上iOS Autolayout

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

hejunbinlan
2016/08/01
8
0
在Swift中使用AutoLayout-VFL(AutoLayout-VFL笔记)

1.背景 iOS开发这几年, UI布局工具从frame到Masonry到SnapKit, sb和xib的AutoLayout也用过, 但是代码版本的AutoLayout倒是没用过, 最近一年, 频频发现一些三方UI组件布局的bug, 作为三方组件...

walden00
07/27
0
0
IOS --Xcode6 自动布局

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

求是科技
2015/03/12
0
0
tableHeaderView的autolayout

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

hejunbinlan
2016/08/04
29
0
Auto Layout + Manual Layout 混用

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

人独立
2015/12/04
252
0

没有更多内容

加载失败,请刷新页面

加载更多

IC-CAD 集成电路设计流程自动化 (绪论)

CAD (Computer Aided Design),计算机辅助设计,指利用计算机及其图形设备帮助设计人员进行设计工作,这个定义同样可以用来近似描述IC公司CAD工程师这个岗位的工作。 早期IC公司的CAD岗位最初...

李艳青1987
4分钟前
0
0
《今日简史:人类命运大议题》的读后感范文3400字

《今日简史:人类命运大议题》的读后感范文3400字: 文:余祥。尤瓦尔.赫拉利,耶路撒冷希伯来大学教授,全球瞩目的新锐历史学家。今年已经拜读其著《人类简史:从动物到上帝》《未来简史:从...

原创小博客
13分钟前
0
0
Eos测试框架EosFactory

EOS Factory包含一个完整的EOS测试框架,可以进行智能合约的开发和测试。由Tokenika于创建于2017年的这个基于Python的EOS测试框架可以轻松地完成智能合约的开发、部署与测试。 如果你希望马上...

汇智网教程
19分钟前
5
0
CompletableFuture get方法一直阻塞或抛出TimeoutException

问题描述 最近刚刚上线的服务突然抛出大量的TimeoutException,查询后发现是使用了CompletableFuture,并且在执行future.get(5, TimeUnit.SECONDS);时抛出了TimeoutException异常,导致接口响...

xiaolyuh
44分钟前
2
0
dubbo 搭建与使用

官网:http://dubbo.apache.org/en-us/ 一,安装监控中心(可以不安装) admin管理控制台,monitor监控中心 下载 bubbo ops 这个是新版的,需要node.js环境,我没有就用老版的了...

小兵胖胖
48分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部