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

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

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

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

问题

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

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

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

  1. imageView.CenterX = view.CenterX * modifier  
  2. 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 的转变。如果不这样做,系统会自动创建约束,这会和我们创建的约束发生冲突。

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

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

  1. func addConstraintFromView(subview: UIView?,  
  2.                          attribute: NSLayoutAttribute,  
  3.                         multiplier: CGFloat,  
  4.                         identifier: String) {  
  5.   if let subview = subview {  
  6.     let constraint = NSLayoutConstraint(item: subview,  
  7.             attribute: attribute,  
  8.             relatedBy: .Equal,  
  9.             toItem: view,  
  10.             attribute: attribute,  
  11.             multiplier: multiplier,  
  12.             constant: 0)  
  13.     constraint.identifier = identifier  
  14.     view.addConstraint(constraint)  
  15.   }  
  16.      

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

  1. // vertical constraint  
  2. addConstraintFromView(heartTop,  
  3.               attribute: .CenterY,  
  4.              multiplier: 0.667,  
  5.              identifier: "heartTop center Y")  
  6.                 
  7. // horizontal constraint  
  8. addConstraintFromView(heartTop,  
  9.               attribute: .CenterX,  
  10.              multiplier: 0.5,  
  11.              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 上找到这篇帖子的代码,它包含IB、代码和 stack view 三个版本,你可以比较下这几个方法。

责任编辑:陈琳 来源: CocoaChina
相关推荐

2009-09-17 13:08:07

NIS配置auto_dire

2021-10-21 09:00:00

机器学习技术工具

2010-09-02 10:16:43

fixedCSS

2009-08-27 09:57:05

Linux谷歌搜索Bing

2023-11-28 15:18:24

Python

2024-04-07 09:00:00

MySQL

2024-02-19 09:27:31

谷歌AI

2011-08-22 13:28:56

FOR XMLSQL Server

2023-09-22 22:27:54

autoC++11

2012-05-01 08:26:00

iOS

2023-11-27 11:51:13

CSS前端

2013-11-28 09:41:36

云会计软件CRM客户关系管理

2009-06-24 07:51:56

Hibernate重复

2011-08-24 09:15:36

SQL Server数FOR XML AUT

2013-11-04 10:51:49

2009-11-18 16:36:13

路由器参数设置

2010-06-10 17:30:58

Linux 测试软件

2010-03-01 14:40:00

Python RSS处

2010-06-11 17:15:18

rsync重启

2019-09-20 08:47:57

DockerLinux软件
点赞
收藏

51CTO技术栈公众号