自动布局:如何隐藏包含子视图的 UIView?

Posted

技术标签:

【中文标题】自动布局:如何隐藏包含子视图的 UIView?【英文标题】:Autolayout: how to hide UIView containing subViews? 【发布时间】:2014-07-11 12:29:56 【问题描述】:

使用新的 Autolayout 隐藏视图的最佳解决方案肯定是为视图创建高度约束,连接它并为其创建一个出口,并将 self.myViewHeightConstriant.constant 更改为 0。但假设视图包含其他一些视图,假设一个 imageView 和它下面的一些标签。现在,imageView 距离顶部 10px 并且具有顶部空间到具有 10px 值的 superview 约束。尝试使用常量 = 0 隐藏容器 UIView 在控制台中显示错误:

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.   
Try this: (1) look at each constraint and try to figure out which you don't expect; 
(2) find the code that added the unwanted constraint or constraints and fix it.   
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't 
understand, refer to the documentation for the UIView property 
translatesAutoresizingMaskIntoConstraints) 
(
   <NSLayoutConstraint:0xc7cedb0 V:[UIView:0xc7ce1e0(0)]>,
   <NSLayoutConstraint:0xc7ceea0 V:[UIImageView:0xc7ce270]-(0)-|   (Names:  '|':UIView:0xc7ce1e0 )>,
   <NSLayoutConstraint:0xc7cef30 V:|-(10)-[UIImageView:0xc7ce270]   (Names: '|':UIView:0xc7ce1e0 )>
)

Will attempt to recover by breaking constraint 

  <NSLayoutConstraint:0xc7ceea0 V:[UIImageView:0xc7ce270]-(0)-|   (Names: '|':UIView:0xc7ce1e0 )> 

猜测问题是容器 UIView 的高度为 0,但 imageView 的顶部空间偏移量为 10px,并且 Autolayout 引擎不了解如何处理这种情况。试图为容器视图设置 clipSubviews 但这没有帮助。有什么想法吗?

更新 几个想法,为 imageView 创建一个出口 topSpaceToSuperView 约束并将其约束也设置为 0 看起来不是很吸引人。应该有比使用多个出口破坏代码更优雅的解决方案...

【问题讨论】:

【参考方案1】:

container.hidden = YES 不能简单吗?

否则,破坏事物的是底部约束。 @"V:|-10-[imageView]|" 告诉容器视图必须至少 10 pts 高。但是@"V:|-10-[imageView]" 会很好。

也许不是将 imageView 锚定到容器的底部,而是为 imageView 的高度设置一个约束。

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[imageView]"
                                        options:nil
                                        metrics:nil
                                          views:views];

[NSLayoutConstraint constraintWithItem:self.imageView
                             attribute:NSLayoutAttributeHeight
                             relatedBy:NSLayoutRelationEqual
                                toItem:self.containerView
                             attribute:NSLayoutAttributeHeight
                            multiplier:1.
                              constant:-10.f];

更新

您在 cmets 中提到 imageView 不是可预测的高度。既然如此,只管理容器的高度可能更容易,但要使用单独的约束:

containerOpen = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[imageView]|"
                                                      options:nil
                                                      metrics:nil
                                                        views:views];

containerClosed = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[containerView(0)]"
                                                        options:nil
                                                       metrics:nil
                                                         views:views];

// Toggle between the constraints to open close the container

- (void)toggleContainer

  [self.containerView.superview removeConstraints:containerOpen];
  [self.containerView.superview removeConstraints:containerClosed];

  self.containerView.isOpen = !self.containerView.isOpen;

  if (self.containerView.isOpen)
    [self.containerView.superview addConstraints:containerOpen];
  else
    [self.containerView.superview addConstraints:containerClosed];

  [self.containerView.superview setNeedsUpdateConstraints];
  [self.containerView setNeedsLayout];
  [self.containerView layoutIfNeeded];

【讨论】:

不,我不能只隐藏,因为容器视图位于另一个容器视图中,并且还有其他视图。隐藏我的容器视图应该将其他容器视图移到顶部,但简单的隐藏不会这样做。另外,imageView是从后端接收的,所以它的高度是动态的,所以我需要把它的顶部和底部贴在superView上,并通过设置containerView的高度来扩展到需要的大小。但是,谢谢,关于底部空间 + imageView 高度的好消息。因此,将拥有并管理 containerViewHeight 和 imageViewHeigh。可能没有其他方法存在。 关于约束的快速说明,我尝试在界面生成器中创建约束,而不是在代码中。将业务逻辑(代码)与可视化部分分开更有意义。但我想这是一个问题...... @Centurion 我在这里又举了一个例子,因为你说你的图像有不同的高度(即容器视图的高度决定了图像的高度)。让我知道这是否有用,否则我会删除它。 另外,我是那些“拒绝使用界面生成器”的人之一。我认为它为自动布局增加了很多 GUI 复杂性,这在一天结束时是一件相当简单的事情。但这只是我。【参考方案2】:

如果您有一个前导、尾随、顶部或底部约束,您可以在隐藏时将关系设置为 LessThanOrEqual,然后在显示时设置为相等。

因为关系是只读的,你可以这样做:

    解除约束 以编程方式将其从 超级视图 设置出口等于一个新的约束, 具有相同的参数,除了您想要的 将约束重新添加到 超级视图

基本上,您在这里所做的只是使该约束足够小,以便“大”视图的高度在隐藏时可以 == 0。

【讨论】:

以上是关于自动布局:如何隐藏包含子视图的 UIView?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自动布局在 UIScrollView 中为视图高度设置动画?

UIScrollView 作为 UIView 的子视图不适用于自动布局

如何移动子视图控制器,同时使用自动布局而不是框架隐藏状态栏?

如何在 UIView 子视图中应用自动布局 NIB 实例

空 UIView 上的自动布局约束无法按预期工作

隐藏视图时如何使用自动布局移动其他视图?