删除特定对象的自动布局约束
我有UIImageView
embedded到UIView
。 我的整个应用程序使用AutoLayout
,但我想删除UIImageView
constraints
。 Xcode
不会允许我删除constraints
,有没有办法禁用它们的特定对象,将它们设置为零,什么?
我同意Xcode自动布局是可怕的使用,如果你想要的东西特定…
我用什么编程去除约束:
[detailsPhotoView removeConstraints:detailsPhotoView.constraints];
在XCode 5中,编辑约束“在构build时删除”有一个选项。 如果启用,约束将在运行时自动删除。 如果你不想要特定的约束,那么这个选项可以让Interface Builder保持高兴。
这里有两个不同的问题:
- 如何使用Xcode来设置一个UIImageView没有约束
- 如何让UIImageView在布局被约束处理时被平移和/或resize。
关于(1),jturton是正确的。 只要你已经在Xcode中启用自动布局,Xcode将保证/要求有足够的约束来唯一确定你的视图的大小和位置。
如果你还没有在Xcode中手工指定足够的约束(通过在布局检查器中以蓝色出现的“用户约束”),那么Xcode将添加新的约束(它以紫色显示),直到有足够的约束来确定布局。
如果UIImageView没有约束,它的布局将不会被确定,所以你不能在Xcode中设置它。 要解决这个问题,你应该做的是使用Xcode来设置IBOutlets到你想要移除的所有约束,然后在你的UIView的awakeFromNib中:或者在你的UIViewController的viewDidLoad中:通过调用removeConstraints:手动移除约束。
但是,现在你的UIImageView的布局是不确定的。 所以在这一点上,您将需要手动添加新的约束,这将允许您移动和调整UIImageView,这使我们质疑(2)。
关于(2),如何调整和移动布局是由约束决定的视图,答案是像往常一样设置手势识别器来检测捏和平移手势,而不是那些调用setFrame的手势识别器:修改视图,他们应该修改确定UIImageView的框架的NSLayoutConstraint的constant
参数,然后调用layoutIfNeeded:,这将导致布局系统立即将修改后的约束转换为新的框架。
所以,举个例子,假设你想用一组与setFrame:calls非常相似的布局约束来操作UIImageView。 在这种情况下,在移除Xcode设置的约束之后,可以向视图添加约束条件,以指定其宽度,高度以及超级视图顶部和左侧的空间。 然后,您的平移手势识别器的操作处理程序将只更新起搏器手势识别器的常量参数,而您的捏手势识别器可以更新高度和宽度约束的常量参数。
(2)的另一种方法,在引擎盖下是相同的,但在实践中可能更容易,就是设置translatesAutoresizingMaskIntoConstraints=YES
。 这将做两件事。 这将导致自动布局系统根据视图的autoresizingMask在视图的超级视图中自动生成约束。 其次 – 关键是! – 这将导致布局系统自动将调用转换为setFrame:修改这些约束。
你不能有约束 – 你必须有足够的约束来明确地确定每个视图的大小和位置
您可以使用Autolay创build一个可resize的视图。
例如,在你的情况下,你可以创build定位约束 – 例如,将图像视图的中心水平和垂直固定在其超视图的中心。
您还可以创build大小约束,水平和垂直。 看到我的答案在这里如何做到这一点。 创build出口到这两个约束(如果使用接口生成器)。 您可以对特定数字的高度和宽度进行限制,也可以使用乘数来确定固定宽高比。
为了响应捏手势,您可以调整两个大小约束的.constant
属性,并调用setNeedsLayout
。 这将调整您的图像视图,同时保持中心固定。
如果您使用上述固定长宽比build议,则使用约束来调整视图的大小实际上比设置框架要简单得多。
你可以打电话
[yourElement removeFromSuperview];
然后打电话
[yourSuperview addSubview:yourElement];
从你的yourElement
删除所有的约束,并将其添加回到视图。
值得一提的是,如果你正在对UIView类别或扩展进行上述操作,则需要在从超级视图中删除之前保存对视图的超级视图的引用:
var theSuperview = self.superview self.removeFromSuperview() theSuperview?.addSubview(self)
你可能还需要使你的元素强大而不是微弱,因为从超级视图中移除可能会导致你失去对它的引用。
如果你只是想从层次结构中删除一个视图,只需调用[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];