删除特定对象的自动布局约束

时间:2012-11-14 21:59:30

标签: iphone uiview uiimageview autolayout

我在UIImageView中嵌入了UIView。我的整个应用都使用AutoLayout,但我想删除constraints的{​​{1}}。 UIImageView不允许我删除Xcode,有没有办法为特定对象禁用它们,将它们设置为零,是什么?

6 个答案:

答案 0 :(得分:88)

我同意如果你想要一些特别的东西,Xcode自动布局是非常糟糕的......

我用什么来以编程方式删除约束:

[detailsPhotoView removeConstraints:detailsPhotoView.constraints];

答案 1 :(得分:25)

在XCode 5中,编辑约束时有一个选项'在构建时删除'。如果启用此选项,则会在运行时自动删除约束。如果您不需要特定约束,可以选择使Interface Builder保持高兴。

答案 2 :(得分:8)

这里有两个不同的问题:

  1. 如何使用Xcode设置无约束的UIImageView
  2. 如何在约束处理布局时允许平移和/或调整UIImageView的大小。
  3. 关于(1),jturton是正确的。只要您在Xcode中启用了自动布局,Xcode就会保证/要求有足够的约束来唯一地确定视图的大小和位置。

    如果你没有在Xcode中手动指定足够的约束(通过布局检查器中以蓝色显示的“用户约束”),那么Xcode将添加它猜测的新约束(以紫色显示),直到有足够的约束确定布局。

    如果UIImageView没有约束,它的布局将无法确定,因此您无法在Xcode中进行设置。要解决这个问题,你应该做的是使用Xcode将IBOutlets设置为你要删除的所有约束,然后在你的UIView的awakeFromNib:或你的UIViewController的viewDidLoad中:你通过调用removeConstraints手动删除约束:。

    但是,现在你的UIImageView的布局是不确定的。所以此时你需要手动添加新的约束,这些约束将允许你移动和调整UIImageView的大小,这让我们回答问题(2)。

    关于(2),如何调整大小&移动一个视图,其布局由约束决定,答案是像往常一样设置手势识别器来检测捏合和放大。 pan手势,但不是那些调用setFrame的手势识别器:修改视图,他们应该修改确定UIImageView框架的NSLayoutConstraint的constant参数,然后调用layoutIfNeeded:,这将导致布局系统立即将修改后的约束转换为新框架。

    因此,例如,假设您想要使用一组与熟悉的setFrame:调用非常相似的布局约束来操作UIImageView。在这种情况下,在通过Xcode删除约束设置之后,您可以向视图添加约束,从约束的顶部和左侧指定其宽度,高度和空间。然后你的平移手势识别器的动作处理程序,只会更新起搏手势识别器的常量参数,你的捏手势识别器可以只更新高度和宽度约束的常量参数。

    另一种做(2)的方法是设置translatesAutoresizingMaskIntoConstraints=YES,它在引擎盖下相同但在实践中可能更容易。这将做两件事。它将使自动布局系统根据视图的autoresizingMask在视图的超级视图中自动生成约束。第二 - 至关重要! - 它将使布局系统自动将对setFrame的调用转换为对这些约束的修改。

答案 3 :(得分:6)

不能没有约束 - 你必须有足够的约束来明确地确定每个视图的大小和位置

可以创建使用Autolayout布局的可调整大小的视图。

例如,在您的情况下,您可以创建定位约束 - 例如,将图像视图的中心水平和垂直地固定在其超视图的中心。

您还可以水平和垂直创建大小约束。有关如何执行此操作,请参阅我的回答here。为这两个约束创建出口(如果使用接口构建器)。您可以具有特定数字的高度和宽度约束,或使用乘数来设置固定的宽高比。

为了响应捏合手势,您可以调整两个大小限制的.constant属性,然后调用setNeedsLayout。这将调整图像视图的大小,同时保持其中心固定。

如果您执行上述固定宽高比建议,则使用约束调整视图大小实际上比设置框架简单得多。

答案 4 :(得分:5)

你可以打电话

[yourElement removeFromSuperview];

然后致电

[yourSuperview addSubview:yourElement];

yourElement中移除所有约束并将其添加回视图。

值得一提的是,如果您在UIView类别或扩展程序上执行上述操作,则需要在从superview中删除之前保存对视图的superview的引用:

var theSuperview = self.superview
self.removeFromSuperview()
theSuperview?.addSubview(self)

你可能还需要使你的元素变强而不是弱,因为从superview中删除可能会导致你失去对它的引用。

答案 5 :(得分:4)

如果您只是想从层次结构中删除视图,只需调用[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。如果约束在他们影响的所有视图的 a 超级视图中,它们将起作用。

[self.view addConstraints: removedConstraints];
[viewToHide setHidden: NO];