删除特定对象的自动布局约束
Posted
技术标签:
【中文标题】删除特定对象的自动布局约束【英文标题】:Remove Auto-Layout Constraints for Specific Object 【发布时间】:2012-11-14 21:59:30 【问题描述】:我在UIView
中嵌入了一个UIImageView
。我的整个应用程序使用AutoLayout
,但我想为UIImageView
删除constraints
。 Xcode
不允许我删除 constraints
,有没有办法为特定对象禁用它们,将它们设置为零,什么?
【问题讨论】:
如果去掉约束,图片视图怎么显示?布局引擎如何知道将它放在哪里?您必须有足够的约束信息来明确地布置整个视图。你到底想达到什么目的? 我想用手势调整图像视图的大小。自动布局约束不允许捏合手势使图像视图变小。 只是为了明确.. 对于特定的 XIB 文件。要关闭自动布局(即“删除约束”),只需单击 ShowFileInspector,然后简单地取消选中“自动布局”。 xib 上的每个项目现在都将像“旧”样式一样工作(带有“粘性箭头”等。) 【参考方案1】:我同意 Xcode 自动布局在你想要一些特别的东西时使用起来很糟糕......
我用来以编程方式删除约束的方法:
[detailsPhotoView removeConstraints:detailsPhotoView.constraints];
【讨论】:
谢谢,这行得通。我已从视图中删除所有约束并使用可视格式语言重新设置它们;上面的代码需要在指定自己的约束之前去掉约束,否则xcode会一直报错 还记得一件事,如果您尝试从 UIImageView 中删除约束,请确保通过代码添加该视图。不要使用 IBoutlet,因为这似乎对您的 setFrame 代码没有任何影响。我刚刚遇到了这个废话。【参考方案2】:在 XCode 5 中,编辑约束时有一个选项“在构建时删除”。如果启用此功能,则在运行时将自动删除约束。如果您不想要特定的约束,可以选择让 Interface Builder 满意。
【讨论】:
最佳答案,简短而准确。 在 XCode 6 中,这现在称为 Intrinsic Size,选项设置为 Placeholder。【参考方案3】:这里有两个不同的问题:
-
如何使用 Xcode 设置无约束的 UIImageView
当 UIImageView 的布局由约束处理时,如何允许平移和/或调整其大小。
关于(1),jturton 是正确的。只要您在 Xcode 中启用了自动布局,Xcode 就会保证/要求有足够的约束来唯一确定您的视图的大小和位置。
如果您没有在 Xcode 中手动指定足够的约束(通过布局检查器中以蓝色显示的“用户约束”),那么 Xcode 将添加它猜测的新约束(以紫色显示)直到有足够的约束确定布局。
如果 UIImageView 没有约束,它的布局将无法确定,所以你不能在 Xcode 中设置它。要解决此问题,您应该使用 Xcode 将 IBOutlets 设置为要删除的所有约束,然后在 UIView 的 awakeFromNib: 或 UIViewController 的 viewDidLoad: 中通过调用 removeConstraints: 手动删除约束。
但是,现在您的 UIImageView 的布局尚未确定。因此,此时您将需要手动添加新的约束,以允许您移动 UIImageView 并调整其大小,这就引出了问题 (2)。
关于 (2),如何调整布局由约束确定的视图的大小和移动,答案是像往常一样设置手势识别器来检测捏合和平移手势,而不是那些调用 setFrame: 的手势识别器来修改视图,他们应该修改 NSLayoutConstraint 的 constant
参数,该参数确定 UIImageView 的框架,然后调用 layoutIfNeeded:,这将导致布局系统立即将修改后的约束转换为新框架。
因此,例如,假设您想使用一组布局约束来操作 UIImageView,这些约束与熟悉的 setFrame: 调用非常相似。在这种情况下,在移除 Xcode 设置的约束后,您可以向视图添加约束,指定其宽度、高度和父视图顶部和左侧的空间。然后,平移手势识别器的动作处理程序只会更新起搏手势识别器的常量参数,而捏合手势识别器只会更新高度和宽度约束的常量参数。
另一种方法是设置translatesAutoresizingMaskIntoConstraints=YES
,这在引擎盖下是相同的,但在实践中可能更容易。这将做两件事。它将导致自动布局系统根据视图的 autoresizingMask 在视图的父视图中自动生成约束。第二——至关重要! – 它将导致布局系统自动将对 setFrame: 的调用转换为对这些约束的修改。
【讨论】:
有一个关于删除约束的 PITA:您需要从“托管”它的视图中删除一个约束。例如。如果您在滚动视图中有图像视图并且它们之间存在约束,那么它就是承载它的滚动。约束不会出现在图像视图的constraints
属性中,在图像视图上调用removeConstraint:
将被静默忽略,并且无法从约束本身获取宿主视图。因此,您必须为滚动视图和约束提供出口,并专门调用[self.scrollView removeConstraint:self.constraint]
。啊!【参考方案4】:
你不能没有约束 - 你必须有足够的约束来明确地调整每个视图的大小和位置
您可以创建使用自动布局布局的可调整大小的视图。
例如,在您的情况下,您可以创建定位约束 - 例如,将图像视图的中心水平和垂直固定在其父视图的中心。
您还可以在水平和垂直方向上创建尺寸限制。请参阅我的回答 here 了解如何执行此操作。为这两个约束创建出口(如果使用界面生成器)。您可以有特定数字的高度和宽度约束,或者使用乘数来制作固定的纵横比。
响应捏合手势,可以调整两个大小约束的.constant
属性,调用setNeedsLayout
。这将调整您的图像视图的大小,同时保持其中心固定。
如果您执行上述固定纵横比建议,则使用约束调整视图大小实际上比设置框架要简单得多。
【讨论】:
我不想在这个容器 UIView 中保留任何东西。我希望 imageView(UIView 中的那个)能够被捏合、移动、平移等,而不需要固定任何东西或有任何大小限制。我会为此设置什么常数?我似乎无法立即实现消除所有约束的想法。 如果您希望它被移动和调整大小,那么您需要定位约束,您还可以使用与我在上面描述大小约束相同的方式在代码中修改的插座。你不能没有约束 - 你必须有足够的约束来明确地确定每个视图的大小和位置。 您是否会将此作为编辑添加到您的回答中:您必须有足够的约束来明确地确定每个视图的大小和位置。那我就接受了。 很遗憾,不,我必须删除自动布局,以便用户可以调整 imageView 的大小。我以后可能会尝试添加它。但是您无法完全删除它们的答案似乎完全正确。感谢您的帮助。 这并没有回答问题,并且删除约束不合法的建议是错误的。可能需要删除 IB 生成的约束以将其替换为无法在 IB 中创建的约束,或者干脆删除所有约束并改用translatesAutoresizingMaskIntoConstraints
。【参考方案5】:
你可以打电话
[yourElement removeFromSuperview];
然后调用
[yourSuperview addSubview:yourElement];
从yourElement
中删除所有约束并将其添加回视图。
值得一提的是,如果您在 UIView 类别或扩展等上执行上述操作,则需要在从超级视图中删除之前保存对视图超级视图的引用:
var theSuperview = self.superview
self.removeFromSuperview()
theSuperview?.addSubview(self)
您可能还需要使 yourElement 强而不是弱,因为从超级视图中删除可能会导致您丢失对它的引用。
【讨论】:
我有一个不遵循 removeConstraints 方法的自定义对象 object.view。这很好地解决了它。没有像我希望的那样以编程方式定义的警告和行为。谢谢亚当!【参考方案6】:如果您只是想从层次结构中删除视图,只需调用[theView removeFromSuperview]
。任何影响它的约束也将被删除。
但是,有时您可能还希望在 暂时 移除视图后将其放回原处。
为了实现这一点,我在UIView
上使用了以下类别。它将视图层次结构从视图v
向上移动到一些最终的容器视图c
(通常是您的视图控制器的根视图)并删除v
外部的约束。这些是与v
同级的约束,而不是仅影响v
的子级的约束。你可以隐藏v
。
-(NSArray*) stealExternalConstraintsUpToView: (UIView*) superview
NSMutableArray *const constraints = [NSMutableArray new];
UIView *searchView = self;
while(searchView.superview && searchView!= superview)
searchView = searchView.superview;
NSArray *const affectingConstraints =
[searchView.constraints filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(NSLayoutConstraint *constraint, NSDictionary *bindings)
return constraint.firstItem == self || constraint.secondItem == self;
]];
[searchView removeConstraints: affectingConstraints];
[constraints addObjectsFromArray: affectingConstraints];
return constraints;
该方法将删除的约束传递回一个数组中,您可以将其保留在某个地方,以便稍后您可以添加回约束。
使用它有点像这样......
NSArray *const removedConstraints = [viewToHide stealExternalConstraintsUpToView: self.view];
[viewToHide setHidden: YES];
稍后,将约束放回去。
从 ios 8 开始,您无需考虑应该将约束放在哪里。就用这个……
[NSLayoutConstraint activateConstraints: removedConstraints];
[viewToHide setHidden: NO];
使用早期版本的 iOS,您无需费力考虑在何处添加约束。然后扔进控制器的self.view
。如果约束在它们影响的所有视图的一个超级视图中,它们就会起作用。
[self.view addConstraints: removedConstraints];
[viewToHide setHidden: NO];
【讨论】:
activateConstraints 自 iOS 8 起可用 @b.zdybowicz - 谢谢,已更新以明确说明。顺便说一句,任何人都可以进行编辑——不过,他们有时会受到审核。以上是关于删除特定对象的自动布局约束的主要内容,如果未能解决你的问题,请参考以下文章