I have designed my custom Cell in IB, subclassed it and connected my outlets to my custom class. I have three subviews in cell content which are: UIView (cdView) and two labels (titleLabel and emailLabel). Depending on data available for each row, sometimes I want to have UIView and two labels displayed in my cell and sometimes only two labels. What I am trying to do is to set constraints that way if I set UIView property to hidden or I will remove it from superview the two labels will move to the left. I tried to set UIView leading constraint to Superview (Cell content) for 10px and UILabels leading Constraints for 10 px to the next view (UIView). Later in my code

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
    
    // ...

    Record *record = [self.records objectAtIndex:indexPath.row];
    
    if ([record.imageURL is equalToString:@""]) {
         cell.cdView.hidden = YES;
    }
}

我把手机藏起来了。cdView和我想要标签移动到左边,但他们在细胞中保持相同的位置。我试着移除细胞。cdView从superview,但它也没有工作。我附上了图片,以澄清我是什么。

我知道如何通过编程来做到这一点,我不是在寻找解决方案。我想要的是在IB中设置约束,我希望如果其他视图被删除或隐藏,我的子视图将动态移动。有可能在IB自动布局中做到这一点吗?

.....

当前回答

对于谷歌人来说:基于Max的回答,为了解决许多人已经注意到的填充问题,我只是增加了标签的高度,并使用这个高度作为分隔符而不是实际的填充。这个想法可以扩展到任何包含视图的场景。

这里有一个简单的例子:

在本例中,我将Author标签的高度映射到适当的IBOutlet:

@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;

当我将约束的高度设置为0.0f时,我们保留了“填充”,因为播放按钮的高度允许它。

其他回答

当set hidden = YES时,将uiview和标签之间的约束连接为IBOutlet,并将优先级成员设置为较小的值

当隐藏属性在它的任何子视图上被改变时,UIStackView自动重新定位它的视图(iOS 9+)。

UIView.animateWithDuration(1.0) { () -> Void in
   self.mySubview.hidden = !self.mySubview.hidden
}

在这段WWDC视频中跳转到11:48进行演示:

自动布局的奥秘,第1部分

这是可能的,但你得多做点工作。首先有几个概念性的东西需要解决:

隐藏视图,即使他们不绘制,仍然参与自动布局,通常保留他们的框架,留下其他相关的视图在他们的地方。 当从它的父视图中移除一个视图时,所有相关的约束也会从该视图层次结构中移除。

在你的情况下,这可能意味着:

如果您将左侧视图设置为隐藏,则标签保持不变,因为左侧视图仍然占用空间(即使它不可见)。 如果你移除左视图,你的标签可能会被模糊地约束,因为你不再对标签的左边有约束。

你需要做的是明智地过度约束你的标签。保留现有的约束(另一个视图有10pts的空间),但添加另一个约束:使标签的左边缘距离其父视图的左边缘有10pts的优先级(默认的高优先级可能会工作得很好)。

然后,当你想让它们向左移动时,完全移除左侧视图。左视图的强制10pt约束将与它相关的视图一起消失,你将只剩下一个高优先级约束,即标签距离它们的父视图10pt。在接下来的布局中,这应该会导致它们向左扩展,直到它们填充了父视图的宽度。

一个重要的警告:如果你想让你的左视图回到图片中,你不仅要把它添加回视图层次结构中,而且还必须同时重新建立它的所有约束。这意味着当视图再次显示时,您需要一种方法将视图与其标签之间的10pt间距限制放回。

对于这个特定的布局,要处理的约束是被隐藏的视图上的'leading'约束。下面的理论在各个方面都适用。

1:设置所有的约束,当所有的视图都是可见的时候,你想让它看起来怎么样。

2:给你想要隐藏的视图添加第二个'leading'约束。这将暂时打破限制。

3:将原来的前导约束的优先级更改为'999' -这将优先级给你的新约束,它将在1000,没有约束将被打破。

4:将新的约束从'leading=leading'更改为' trails =leading'。这将移动您想要隐藏的视图,使其远离父视图的前缘。

5:切换新约束的isActive值现在会切换,如果它在视图中或在视图外。在设置可见性为true/false的同时,将其设置为true/false。例如:

@IBOutlet var avatar:UIImage!
@IBOutlet var avatarLeadHid:NSLayoutConstraint!

func hideAvatar() {
  self.avatar.isHidden = true
  self.avatarLeadHid.isActive = true
}

func showAvatar() {
  self.avatar.isHidden = false
  self.avatarLeadHid.isActive = false
}

额外的好处:你可以调整新的hide -constraint的“常量”值,以改变视图隐藏时使用的填充/边距。这个值可以是负数。

额外的好处:只需切换hide -constraint上的“Installed”复选框,就可以在不运行任何代码的情况下,在Interface Builder中看到你的布局。

进一步帮助:我做了一个视频,展示了我做得更好的点列表:https://youtu.be/3tGEwqtQ-iU

以下是我如何重新对齐我的uiviews来得到你的解决方案:

拖拽一个UIImageView放到左边。 拖拽一个UIView并把它放到UIImageView的右边。 在UIView中拖放两个uilabel,它的前导约束和尾随约束为零。 将包含2个标签的UIView的前置约束设置为superview而不是UIImagView。 如果UIImageView被隐藏,设置前置约束常量为10像素到superview。ELSE,设置前置约束常量为10px + UIImageView。宽度+ 10像素。

我自己制定了一个拇指规则。当你必须隐藏/显示任何约束可能受到影响的uiview时,在uiview中添加所有受影响/依赖的子视图,并以编程方式更新其前/后/上/下约束常量。