我有一个UIView,通过几个约束放在屏幕上 . 一些约束由superview拥有,其他约束由其他祖先拥有(例如,可能是UIViewController的view属性) .
我想删除所有这些旧约束,并使用新约束将其置于新的位置 .
如果不为每个约束创建一个IBOutlet并且必须记住哪个视图拥有所述约束,我该怎么做呢?
详细说来,天真的方法是为每个约束创建一堆IBOutlet,然后涉及调用代码,例如:
[viewA removeConstraint:self.myViewsLeftConstraint];
[viewB removeConstraint:self.myViewsTopConstraint];
[viewB removeConstraint:self.myViewsBottomConstraint];
[self.view removeConstraint:self.myViewsRightConstraint];
这段代码的问题在于即使在最简单的情况下,我也需要创建2个IBOutlet . 对于复杂的布局,这可以轻松达到4或8个所需的IBOutlet . 此外,我需要确保在正确的视图上调用我的删除约束的调用 . 例如,假设 myViewsLeftConstraint
归 viewA
所有 . 如果我不小心打电话给 [self.view removeConstraint:self.myViewsLeftConstraint]
,什么都不会发生 .
Note: 方法constraintsAffectingLayoutForAxis看起来很有前景,但仅用于调试目的 .
Update: 我收到的许多答案涉及 self.constraints
, self.superview.constraints
或其中的一些变体 . 这些解决方案不起作用,因为这些方法仅返回视图所拥有的约束,而不返回影响视图的约束 .
要澄清这些解决方案的问题,请考虑以下视图层次结构:
-
祖父
-
父亲
-
我
-
儿子
-
女儿
-
兄弟
-
叔叔
现在假设我们创建了以下约束,并始终将它们附加到最近的共同祖先:
-
C0:我:和儿子一样(由我拥有)
-
C1:我:宽度= 100(由我拥有)
-
C2:我:和兄弟一样高(父亲拥有)
-
C3:我:和叔叔一样(由祖父拥有)
-
C4:我:和祖父一样(由祖父拥有)
-
C5:兄弟:和父亲一样(由父亲拥有)
-
C6:叔叔:和祖父一样(由祖父拥有)
-
C7:儿子:和女儿一样(由我拥有)
现在假设我们要删除所有影响 Me
的约束 . 任何适当的解决方案应该删除 [C0,C1,C2,C3,C4]
而不是其他 .
如果我使用 self.constraints
(其中self是我),我将获得 [C0,C1,C7]
,因为这些是我拥有的唯一约束 . 显然,删除它是不够的,因为它缺少 [C2,C3,C4]
. 此外,它正在不必要地删除 C7
.
如果我使用 self.superview.constraints
(其中self是我),我将获得 [C2,C5]
,因为这些是父拥有的约束 . 显然我们无法删除所有这些,因为 C5
与 Me
完全无关 .
如果我使用 grandfather.constraints
,我会得到 [C3,C4,C6]
. 同样,我们无法删除所有这些因为 C6
应保持完整 .
蛮力方法是遍历每个视图的祖先(包括它自己),并查看 firstItem
或 secondItem
是否是视图本身;如果是这样,删除该约束 . 这将导致正确的解决方案,返回 [C0,C1,C2,C3,C4]
,并且只返回那些约束 .
但是,我希望有一个更优雅的解决方案,而不是遍历整个祖先列表 .
12 回答
这种方法对我有用:
完成后,您的视图将保持原样,因为它会创建自动调整约束 . 当我不这样做时,视图通常会消失 . 此外,它不仅从超级视图中删除约束,而且一直向上遍历,因为在祖先视图中可能存在影响它的约束 .
您可以通过执行以下操作删除视图中的所有约束:
编辑:要删除所有子视图的约束,请在Swift中使用以下扩展名:
到目前为止我找到的唯一解决方案是从超视图中删除视图:
这看起来像删除了影响其布局的所有约束,并准备好添加到superview并附加新的约束 . 但是,它也会错误地从层次结构中删除任何子视图,并错误地删除
[C7]
.在Swift中:
根据 Apple Developer Documentation ,有两种方法可以实现这一目标
1. NSLayoutConstraint.deactivateConstraints
2. UIView.removeConstraints(已弃用> = iOS 8.0)
小贴士
使用
Storyboard
s或者XIB
在配置场景中提到的约束时会非常痛苦,您必须为要删除的每个约束创建IBOutlet . 即便如此,大部分时间Interface Builder
都会产生比它解决的更多麻烦 .因此,当具有非常动态的内容和不同的视图状态时,我建议:
以编程方式创建视图
布局并使用NSLayoutAnchor
将稍后可能删除的每个约束附加到数组
每次应用新状态前清除它们
Simple Code
参考文献
NSLayoutConstraint
UIView
详情
Xcode 9.1,Swift 4
解决方案
用法
完整样本
结果
我使用以下方法从视图中删除所有约束:
.h文件:
.m文件:
您也可以在我的博客上read this post更好地了解它的工作原理 .
如果你需要更精细的控制,我建议切换到Masonry,这是一个强大的框架类,你可以在需要以编程方式正确处理约束时使用它 .
一个Swift解决方案:
通过所有父母是很重要的,因为两个元素之间的约束由共同的祖先保持,所以只是清除this answer中详述的超级视图是不够好的,并且您可能最终会在以后遇到不好的意外 .
(截至2017年7月31日)
SWIFT 3
Objective C
这是快速删除UIView上存在的所有约束的最简单方法 . 只需确保将UIView添加回新的约束或之后的新帧=)
基于之前的答案(快速4)
当您不想抓取整个层次结构时,可以使用immediateConstraints .
你可以使用这样的东西:
基本上,这是对viewA的superview上的所有约束进行枚举,并删除与viewA相关的所有约束 .
然后,第二部分使用viewA的约束数组从viewA中删除约束 .
这是从特定视图禁用所有约束的方法