文档章节

哪里写Autolayout布局最合适?

hejunbinlan
 hejunbinlan
发布于 2016/07/29 13:29
字数 1894
阅读 61
收藏 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
博文 586
码字总数 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

没有更多内容

加载失败,请刷新页面

加载更多

为什么 vue 默认导出的是 vue.common.js,它和 vue.js 的区别在哪里,又有什么关系?

这个问题在囧克斯的博客中有提到。 Vue 最早会打包生成三个文件,一个是 runtime only 的文件 vue.common.js,一个是 compiler only 的文件 compiler.js,一个是 runtime + compiler 的文件 ...

粒子数反转
28分钟前
3
0
php正则表达式替换图片地址

<?php /*PHP正则提取图片img标记中的任意属性*/ $str = '<center><img src="/uploads/images/20100516000.jpg" height="120" width="120"><br />PHP正则提取或更改图片img标记中的任意属性<......

mdoo
32分钟前
2
0
一个简单的系统监控脚本

一个简单的系统信息监控脚本 #!/bin/bash# DATE:20181018# System monitor by Kxvzinterval=5while :doecho '==========================================================...

Kxvz
34分钟前
2
0
七牛云助你度寒冬 | 每天 10:24, 新用户抢全额免单

近年来,中美贸易战、股市暴跌、房地产变天、人民币贬值等等,企业艰难生存于冰川夹缝之中,融资发展难上加难。 凛冬将至, 七牛云特此推出免单好礼,为新用户(2018 年 10 月 10 日后新注册...

七牛云
36分钟前
1
0
Echarts X轴刻度标签换行显示

xAxis: [ { 'type':'category', splitLine: {show: false}, axisLabel: { show: true,//是否显示 interval:0,//强制显示 ......

郭周园
41分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部