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自动布局中做到这一点吗?

.....

当前回答

我最终创建了2个xib。一个有左视图,一个没有。我在控制器中注册了这两个,然后决定在cellForRowAtIndexPath期间使用哪个。

它们使用相同的UITableViewCell类。缺点是在xib之间有一些重复的内容,但是这些单元格非常基本。好处是我不需要一堆代码来手动管理删除视图、更新约束等。

一般来说,这可能是一个更好的解决方案,因为它们在技术上是不同的布局,因此应该有不同的xib。

[self.table registerNib:[UINib nibWithNibName:@"TrackCell" bundle:nil] forCellReuseIdentifier:@"TrackCell"];
[self.table registerNib:[UINib nibWithNibName:@"TrackCellNoImage" bundle:nil] forCellReuseIdentifier:@"TrackCellNoImage"];

TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:(appDelegate.showImages ? @"TrackCell" : @"TrackCellNoImage") forIndexPath:indexPath];

其他回答

我的项目使用了UILabel的自定义@IBDesignable子类(以确保颜色,字体,插图等的一致性),我已经实现了如下内容:

override func intrinsicContentSize() -> CGSize {
    if hidden {
        return CGSizeZero
    } else {
        return super.intrinsicContentSize()
    }
}

这允许label子类参与自动布局,但隐藏时不占用空间。

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

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

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

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

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

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

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

在我的例子中,我将高度约束的常数设置为0.0f,并将隐藏属性设置为YES。

为了再次显示视图(带有子视图),我做了相反的事情:我将高度常数设置为非零值,并将隐藏属性设置为NO。

在运行时期间添加或删除约束是会影响性能的重量级操作。然而,有一个更简单的选择。

对于希望隐藏的视图,设置宽度约束。用一个领先的水平间隙约束其他视图到该视图。

要隐藏,请将width约束的.常量更新为0.f。其他视图将自动向左移动以占据位置。

更多细节请看我的另一个答案:

如何在运行时改变标签约束?

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

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

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

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