在 iOS 上,边距、边缘插入、内容插入、对齐矩形、布局边距、锚点......有啥区别?
Posted
技术标签:
【中文标题】在 iOS 上,边距、边缘插入、内容插入、对齐矩形、布局边距、锚点......有啥区别?【英文标题】:On iOS, what are the differences between margins, edge insets, content insets, alignment rects, layout margins, anchors...?在 iOS 上,边距、边缘插入、内容插入、对齐矩形、布局边距、锚点......有什么区别? 【发布时间】:2016-10-14 07:01:56 【问题描述】:ios 社区中似乎有几个不同的选项/术语和人们在布局方面使用(例如 UIEdgeInsets 是一种类型,但有时我听到/读到“设置插图”或布局边距与布局指南)。
我总能找到一个可行的选项。但我永远不确定我是否使用了正确的工具来完成这项工作。
有人可以帮助阐明布局的这些不同方面以及何时以最佳方式使用每个方面吗?
【问题讨论】:
【参考方案1】:对不起,如果这是一个无聊的答案,但我觉得 Apple 开发人员文档非常擅长描述每个 UIView 属性的用途。
至于当您有多种方法/选项有效时,实现布局的最佳方式是什么……这确实是风格/意见的问题。我会关注以下标准来做出决定:
-
考虑消除最难维护/调试/理解的选项
想象一下有人全新加入您的团队或有人继承您的代码 - 他们在调试哪种实现时会遇到困难,为什么?
考虑消除使布局更难重新排列/展开/编辑的选项
考虑消除与应用其余部分不一致的选项(这种情况又回到第一点)
考虑消除违背 Apple 意图的选项(请参阅文档/WWDC 讨论以了解他们的意图)。
团队可以通过此标准共同努力,就每个场景中的“我们如何布局 UI”达成一致。我猜您要的是此类讨论的总和产品:各种布局样式指南。
根据我的经验,这一直是在我工作过的团队中有机地发展起来的,而且事情并没有真正写下来。上面的第 3 点还有很多内容。
问题中描述的类的 Apple 文档摘录:
在UILayoutGuide:
使用布局指南替换您可能创建的虚拟视图,以表示用户界面中的视图间空间或封装。传统上,有许多自动布局技术需要虚拟视图。
...
UILayoutGuide 类旨在执行以前由虚拟视图执行的所有任务,但以更安全、更有效的方式执行。
在layoutMargins:
在 iOS 11 及更高版本中,使用 directionalLayoutMargins 属性而不是此属性来指定布局边距。
在directionalLayoutMargins:
使用此属性可指定此视图及其子视图的边缘之间的所需空间量(以磅为单位)。前导边距和后边距根据当前布局方向适当地应用于左边距或右边距。
在contentInset:
使用此属性可扩展内容与内容视图边缘之间的空间。大小的单位是点。默认值为 UIEdgeInsetsZero。
开启topAnchor:
使用此锚点创建具有视图顶部边缘的约束。您只能将此锚点与其他 NSLayoutYAxisAnchor 锚点结合使用。有关详细信息,请参阅 NSLayoutAnchor。
开启NSLayoutAnchor
使用这些约束以编程方式使用自动布局定义您的布局。不要直接创建 NSLayoutConstraint 对象,而是从您希望约束的 UIView、NSView 或 UILayoutGuide 对象开始,然后选择该对象的锚属性之一。这些属性对应于 Auto Layout 中使用的主要 NSLayoutConstraint.Attribute 值,并提供适当的 NSLayoutAnchor 子类来为该属性创建约束。使用锚的方法来构造你的约束。
【讨论】:
我对文档不感兴趣。我对它的实际用例感兴趣。你会在哪里使用一个,而不是另一个。提供一些可能不是正确选择的图像可能是个好主意 我认为这在列出的 4 个标准中得到了解决,@Honey 我的问题是我不应该在哪里使用锚并使用另一个......为什么?当锚不起作用时,我需要它的示例。【参考方案2】:希望您能从以下链接/图片中获得信息。
您将能够从下面的链接中推断出有关布局参数的所需信息。
alignment rects.
content inset and offsetexample 2
margins
【讨论】:
【参考方案3】:在阅读本文之前和之后查看此UIKit: Apps for Every Size and Shape。可能还想看看这里的笔记。
作为赏金提供者...我想说我的大部分困惑来自于没有正确理解 UILayoutGuide
类。这是关键,但也很简单。
我先介绍一个problem:
在过去,如果您需要像这样限制这些圆圈:
然后您必须创建 clear UIViews 并将它们添加为您的子视图,然后将您的约束添加到它们,如下所示:
今天您不需要将它们添加为您的子视图。你可以改为使用
布局指南
要创建布局指南,您必须执行以下步骤:
-
实例化一个新的布局指南。
通过调用视图的
addLayoutGuide(_:)
方法将布局指南添加到视图。
使用自动布局定义布局指南的位置和大小。
您可以使用这些指南来定义布局中元素之间的空间。以下示例显示了用于定义一系列视图之间的相等间距的布局指南。
步骤:
let space1 = UILayoutGuide()
view.addLayoutGuide(space1)
let space2 = UILayoutGuide()
view.addLayoutGuide(space2)
space1.widthAnchor.constraintEqualToAnchor(space2.widthAnchor).active = true
saveButton.trailingAnchor.constraintEqualToAnchor(space1.leadingAnchor).active = true
cancelButton.leadingAnchor.constraintEqualToAnchor(space1.trailingAnchor).active = true
cancelButton.trailingAnchor.constraintEqualToAnchor(space2.leadingAnchor).active = true
clearButton.leadingAnchor.constraintEqualToAnchor(space2.trailingAnchor).active = true
布局指南也可以充当黑匣子,包含许多其他视图和控件。这使您可以封装部分视图,将布局分解为模块化块。
三个有趣的笔记:
-
如果您使用“查看调试层次结构”,那么您将看到更多
UILayoutGuide
的实例
就像 UIView 一样,UILayoutGuide instance 具有 所有 种锚点
至于为什么不直接创建虚拟 UIView 并通过创建 UILayoutGuides:“将虚拟视图添加到视图层次结构会产生许多成本。首先,创建和维护视图本身会产生成本。其次,虚拟视图是视图层次结构的完整成员,这意味着它会增加层次结构执行的每项任务的开销。最糟糕的是,不可见的虚拟视图可以截获旨在发送给其他视图的消息,从而导致难以处理的问题找到。”
更多信息请见documentation。
topLayoutGuide
与 safeAreaLayoutGuide
topLayoutGuide(已弃用)
它已被弃用,但出于学习目的:A UIViewController
有 2 个虚拟框。顶部的 1 个属性名为 topLayoutGuide
,底部的另一个属性名为 bottomLayoutGuide
。 viewController 本身没有任何左侧/前导或右/尾侧的指南。这两个都是UILayoutGuide
的实例
如果限制为 view.topAnchor 即:
tableView.topAnchor.constraint(equalTo: view.topAnchor)
tableView 不从导航栏的底部开始。注意导航栏后面的橙色...
但是,如果您将其限制为 topLayoutGuide.bottomAnchor
即:
tableView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor)
那么tableView从navigationBar的底部开始
根据您的布局设计,您可能希望您的内容在导航栏下方模糊。
这个想法是您可以边到边显示您的内容。和 它会在酒吧下面重叠,这样你就可以得到这些漂亮的彩色 通过条形模糊您的内容
有关更多信息,请参阅此moment from WWDC 和此问题here。我认为解决方案并不完全相关,只是问题中的图像。
safeAreaLayoutGuide
iOS11 起
Apple 已弃用
topLayoutGuide
和bottomLayoutGuide
。所以 你现在有一个名为safeAreaLayoutGuide
在 UIView 实例上。 UIViewController 不再有任何这些...... 从useyourloaf 复制的视觉比较:
旁注:如果您使用故事板,那么将您的视图对齐到 topLayoutGuide 或 safeAreaLayoutGuide 的顶部将呈现相同的效果。如果您不使用情节提要(以编程方式进行),那么您将不得不在 iOS11 和 LessThaniOS11 之间跳舞,并拥有 2 个不同版本的代码
有关safeAreaLayoutGuide
的更多信息,我强烈建议您设置Apple's article on: Positioning Content Relative to the Safe Area
注意: safeAreaLayoutGuide
是一个 UIView 属性。 topLayoutGuide
是 UIViewController 属性。
layoutMarginsGuide
UIView
只有 1 个虚拟框。该属性被命名为 layoutMarginsGuide
。但与UIViewController
不同,它不位于顶部或底部。它只是位于UIView
的中心,有 8 点填充/插入(从所有 4 个侧面)。那么这在哪里有用?:如果你 don,你会使用它'不 希望你的 textView 被限制在 UIView 实例的边缘。这将改善阅读体验。或者,不是将按钮约束到其父视图的leadingAnchor 并使其看起来很丑,而是向锚点添加8 个点……即将按钮约束到leadingAnchor,然后添加8 个常量点。
someButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8)
但是等等,有一个更简单的方法。只需使用 Apple 推荐的边距,即使用:
someButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor)
另见
中提供的示例
documentation。 可以找到一个很好的 Raywenderlich 教程 here
readableContentGuide
与layoutMarginGuide
略有不同。两者都是 UIView 的属性。有时它们是相同的,有时它们不是。它的目的是:
本布局指南定义了一个易于阅读的区域,无需 强迫用户移动他们的头来跟踪线条
欲了解更多信息,请参阅 this moment from WWDC: building Adaptive layout 和这个很棒的 useyourloaf tutorial。
在 iPhone 7 Plus 的纵向上,可读的内容指南是相同的
作为视图的边距指南,但在横向中会有更多的白色 文本视图两侧的空间。在 iPad 横屏上, 空白显着增加。
边距大小取决于系统的动态类型。越大的 字体,指南将越宽。
来自RayWenderlich
在下图中,青色锚定到layoutMarginGuide
,但绿色锚定到readableContentGuide
:
UIEdgeInsets
如果您想更改您的layoutMarginsGuide
,即将所需的边距从 8 点更改为 16 点,那么您必须更改layoutMargins
的值,然后更改layoutMarginsGuide
的锚点会自动更新。
UIEdgeInsets
只是您的layoutMargins
的类型。 layoutMargins
是UIView
类的属性name
someview.layoutMargins = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)
我发现这段代码☝️唯一起作用的地方是viewDidLayoutSubviews
内部。更多信息请参见here
Anchors
它们是基础,但没有什么特别之处。它们是任何 UIView/UILayoutGuide 的最远边缘。 UIView 和 UILayoutGuide 实例都有它。您约束的一切最终都会使用锚点进行约束,这只是您将其锚定到什么实体的锚点的问题。它可能是safeAreaLayoutGuide
的锚点,也可能是layoutMarginGuide
的锚点,也可能是topLayoutGuide
的锚点,也可能是view
的锚点。 (虽然你也可以将你的 heightAnchor 锚定为 50,所以在这种情况下没有另一个锚)
layoutMarginsGuide
和 Anchors
之间的出色视觉比较可以从 answer 找到。它是使用故事板完成的,因此更容易理解。
contentInsets
虽然理解很重要,但这是一个完全不同的讨论,与其他讨论无关。它特定于 UIScrollViews。更多内容见this great article
结论
为了安全并确保一切都在内部您的视图使用safeAreaLayoutGuide
。如果您想使用系统提供的边距来获得更好的视图布局或有一些填充,那么请使用layoutMarginGuide
,如果您想让事情更具可读性readableContentGuide
。
readableContentGuide
的大小始终小于或等于layoutMarginGuide
。layoutMarginGuide
的大小总是小于或等于safeAreaLayoutGuide
layoutMargins
与 CSS 的填充非常相似。 safeAreaLayoutGuide
类似于 CSS 边距。我不知道readableContentGuide
是否有任何CSS等价物
附录:ContentInset 与 contentOffset
它们用于滚动视图,与答案的其余部分无关。至于contentInset
&contentOffset
是什么,请看this moment from WWDC 2018: UIKit: Apps for Every Size and Shape
。视频非常简单。另请参阅下面的 Karthik 的回答。话虽如此,您必须完全了解 scrollView 的工作原理并了解 contentSize
是什么,否则它会很复杂。有关contentSize
和scrollView 的更多信息,请参阅Vacawama's answer here
【讨论】:
safeAreaLayoutGuide
被更好地描述为类似于 CSS 边距。将layoutMargins
比作填充是恰当的。以上是关于在 iOS 上,边距、边缘插入、内容插入、对齐矩形、布局边距、锚点......有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章