使用Auto Layout处理比例间距问题

Auto Layout 是一个掌握起来很具有挑战性的东西。iOS 9引入的 Stack Views和 layout 锚点有一些帮助,但是明白如何创建特定的 layout仍有一定难度。

在这篇文章中我想着眼于一个经常出现的情形: 你需要沿一个轴向按固定比例放置视图。可能并不是十分明显, 但是这个需求可以通过 一个multiplier中心对齐来轻松实现,它是一种在有无Stack Views情况下都可以使用的技术。

问题

设想我们要构建这样一个布局,上面有两排图片视图,都是基于父视图宽度和高度的某一百分比放置。之所以使用图片视图, 是因为如果意外地把它们拉伸或压缩了, 可以十分明显得看出来。

当视图适应不同的屏幕大小时, layout 会保持相同的比例。下面是同一个视图在横屏模式下的情形:

一旦你看出来我们是基于视图中心进行对齐的,你就会发现我们可以只使用中心对齐约束来创建整个布局。对每个imageView,我们需要一对约束来确定其在X轴和Y轴的位置,一般的格式是这样的:

imageView.CenterX = view.CenterX * modifier
imageView.CenterY = view.CenterY * modifier

modifier参数将imageView放置在父视图尺寸的某个百分比的位置上,如下所示:

寓教于乐。这里有三种方式来创建该布局,第一是使用 IB, 第二是用代码添加约束,第三是使用 stack view.

使用Interface Builder创建约束

对每个 image view 我们需要添加两个约束。使用文档大纲工具栏或者直接在视图画布中按住 control 键从 image view 中拖拽到父视图上。每一个都添加一个“Center Horizontally in Container”和“Certer Vertically in Container”约束。

现在, 编辑每个约束来设置我们需要的百分比例。下面是左上角的红心图片视图的水平和垂直约束设置:

注意这也是给我们的约束添加identifiers 的好时机。完成后,你应该添加了10个约束,如下所示:

以代码形式创建约束

在看添加约束的代码之前,我要提下一个常见的错误,当使用代码添加视图时, 你需要关闭视图的 autoresizing mask 向 constraints 的转变。如果不这样做,系统会自动创建约束,这会和我们创建的约束发生冲突。

//...code to create image view...
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)

有几种创建这些约束的方法,我将会在视图控制器的 viewDidLoad 方法中创建. 一个简单的辅助函数会使创建每个 NSLayoutConstraint 的过程不那么麻烦:

func addConstraintFromView(subview: UIView?,
                         attribute: NSLayoutAttribute,
                        multiplier: CGFloat,
                        identifier: String) {
  if let subview = subview {
    let constraint = NSLayoutConstraint(item: subview,
            attribute: attribute,
            relatedBy: .Equal,
            toItem: view,
            attribute: attribute,
            multiplier: multiplier,
            constant: 0)
    constraint.identifier = identifier
    view.addConstraint(constraint)
  }
   
}

这样就可以创建并添加一个相对于父视图的约束 (使用视图控制器的 view 属性)。NSLayoutAttribute 参数在水平约束中为 .CenterX,在竖直约束中为 .CenterY。例如,下面是上面一行的红心图片视图的约束:

// vertical constraint
addConstraintFromView(heartTop,
              attribute: .CenterY,
             multiplier: 0.667,
             identifier: "heartTop center Y")
              
// horizontal constraint
addConstraintFromView(heartTop,
              attribute: .CenterX,
             multiplier: 0.5,
             identifier: "heartTop center X")

剩下的和这个类似,全部设置见示例代码。

使用Stack View呢?

无论何时只要你遇到水平或垂直布局的问题,你就要想到 stack view。向 stack view 中添加 image views 是很简单的,但是如何配置呢? 我们不想让stack view中堆满views, 所以 Axis 选择水平轴向, 使用“Equal Spacing”分布方式:

现在我们需要约束 stack view 的大小和位置:

  • 使用和设置图片视图竖直位置相同的方式设置每个 stack view 的竖直位置。使用modifier中心约束 (例如顶部 stack view 使用 stackView.centerY = 0.667 * superview.centerY 约束)。

  • 向每个 stack view 添加一个水平居中的约束。

  • 最后的约束需要一点小小的技巧,我们需要确定 stack view 的宽度,使用 stack view 的 leading 和 trailing 边缘是最简单的方式:

左上的 image view 的中心应该是父视图中心的 0.5 倍. 那么我们需要 stack view 的左边向左移动image view 宽度的一半. image view 大小时 100x100, 所以我们需要在约束中减去 50:

注意在 IB 中添加这个约束时你需要改变第二项为 superview center,equal spacing 分布方式将会为我们修正 trailing 位置. 用类似的方法处理下方的 stack view,于是我们最终结果如下:

这是我发现的一种用代码添加约束要比在IB中编辑简单得多的一种情形,尤其是当我们可以在运行时计算 image view 的大小时。

2016-01-31 更新: 还有一个更简单的方法,为最左边图片的中心添加一个约束,stack view 会改变大小来适应,而不需要计算图片的大小。详见代码。

补充阅读

你可以在 GitHub CodeExamples( https://github.com/kharrison/CodeExamples/tree/master/AutoLayout )上找到这篇帖子的代码,它包含IB、代码和 stack view 三个版本,你可以比较下这几个方法。

使用Auto Layout处理比例间距问题的更多相关文章

  1. WWDC2016 Session笔记 - Xcode 8 Auto Layout新特性

    目录 1.Incrementally Adopting Auto Layout 2.Design and Runtime Constraints 3.NSGridView 4.Layout Feedb ...

  2. 【转】使用 Auto Layout 的典型痛点和技巧

    layoutIfNeeded()强制立刻更新布局 原文网址:http://www.jianshu.com/p/0f031606e5f2 官方文档:Auto Layout Guide 加上去年WWDC上 ...

  3. iOS之Xcode8 Auto Layout新特性

    目录 1.Incrementally Adopting Auto Layout 2.Design and Runtime Constraints 3.NSGridView 4.Layout Feedb ...

  4. WWDC2016 Session笔记 – Xcode 8 Auto Layout新特性

    目录 1.Incrementally Adopting Auto Layout 2.Design and Runtime Constraints 3.NSGridView 4.Layout Feedb ...

  5. Swift语言Auto Layout入门教程:上篇

    原文:Beginning Auto Layout Tutorial in Swift: Part 1/2,译者:@TurtleFromMars 开始用自动布局约束的方式思考吧! 更新记录:该教程由Br ...

  6. iOS发展 ---- 至iPhone 6自适应布局设计 Auto Layout

    Apple从iOS 6增加了Auto Layout后開始就比較委婉的開始鼓舞.建议开发人员使用自适应布局,可是到眼下为止,我感觉大多数开发人员一直在回避这个问题,无论是不是因为历史原因造成的,至少他们 ...

  7. (七)unity4.6Ugui中国教程文档-------摘要-UGUI Auto Layout

    大家好,我是太阳广东. 转载请注明出处:http://write.blog.csdn.net/postedit/38922399 更全的内容请看我的游戏蛮牛地址:http://www.unityman ...

  8. 【转】(七)unity4.6Ugui中文教程文档-------概要-UGUI Auto Layout

    原创至上,移步请戳:(七)unity4.6Ugui中文教程文档-------概要-UGUI Auto Layout 6. Auto Layout Rect Transform布局系统是足够灵活,可以处 ...

  9. iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束

    http://blog.csdn.net/pucker/article/details/41843511 上一篇文章<iOS 8界面自动布局系列-1>简要介绍了iOS界面布局方式的前世今生 ...

随机推荐

  1. 洛谷P1418 选点问题

    P1418 选点问题 74通过 240提交 题目提供者tinylic 标签云端 难度普及+/提高 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 非常重要!! 90分的点这里 题 ...

  2. 【CCF】无线网络 搜索

    [思路] 多个起点同时四周扩展广搜,注意会爆int [AC] #include<iostream> #include<cstdio> #include<cstring&g ...

  3. SqlLite 安装与使用

    一.安装文件 官方下载地址: http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki 选择要下载的类库文件:sqli ...

  4. 【POJ1276】Cash Machine(多重背包单调队列优化)

    大神博客转载http://www.cppblog.com/MatoNo1/archive/2011/07/05/150231.aspx多重背包的单调队列初中就知道了但一直没(不会)写二进制优化初中就写 ...

  5. Java面试进阶部分集合

    框架基础 反射:反射是Java开发的一类动态相关机制.因为本身Java语言并不是一款动态语言,如果我们想要得到程序动态的效果,因此便引入了反射机制这一概念. 怎么表达反射? 能用反射做什么? PS:某 ...

  6. unix网络编程第2章

    time_wait状态  可靠地实现tcp全双工连接的终止; (假设客户端先关闭).服务端再关闭,服务端将发送fin ,客户端此时进入time_wait状态.客户端接收到fin.将回一个ack.如果这 ...

  7. (转):从内核代码聊聊pipe的实现

    来源: http://luodw.cc/2016/07/09/pipeof/ 用linux也有两年多了,从命令,系统调用,到内核原理一路学过来,我发现我是深深喜欢上这个系统:使用起来就是一个字&quo ...

  8. 关于unity3d插件的自动打包

    开发中,迩可能会遇到在xcode里添加一些需要调用原生api的方法,可能是game center,可能是内购之类的,但是这些插件实在太多了,所以迩大可不必自己写这些插件,问题在于,国内的一些插件,像9 ...

  9. 标题:如何使用ShareSDK实现Cocos2d-x的Android/iOS分享与授权

    Cocos2DX 简介 Cocos2d-x是一套成熟的开源跨平台游戏开发框架.其引擎提供了图形渲染.GUI.音频.网络.物理.用户输入等丰富的功能,被广泛应用于游戏开发及交互式应用的构建.引擎的核心采 ...

  10. 洛谷——P1126 机器人搬重物

    P1126 机器人搬重物 题目描述 机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格,有 ...