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

.....

当前回答

对于那些只支持iOS 8+的用户,有一个新的布尔属性激活。这将有助于仅动态启用所需的约束

附:约束出口必须是强的,而不是弱的 例子:

@IBOutlet weak var optionalView: UIView!
@IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint!
@IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!

func showView() {
    optionalView.isHidden = false
    viewIsVisibleConstraint.isActive = true
    viewIsHiddenConstraint.isActive = false
}

func hideView() {
    optionalView.isHidden = true
    viewIsVisibleConstraint.isActive = false
    viewIsHiddenConstraint.isActive = true
}

此外,要修复故事板中的错误,您需要取消这些约束之一的“已安装”复选框。 UIStackView (iOS 9+) 另一个选择是用UIStackView包装你的视图。一旦视图被隐藏,UIStackView将自动更新布局

其他回答

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

这里有一个简单的例子:

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

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

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

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

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

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

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

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

为了帮助别人,我构建了一个使用可视格式约束的helper类。我在我当前的应用程序中使用它。

AutolayoutHelper

它可能有点适合我的需要,但您可能会发现它很有用,或者您可能想修改它并创建自己的帮助器。

我必须感谢Tim的回答,这个关于UIScrollView和本教程的回答。

我认为这是最简单的答案。请验证它是否有效:

        StackFullView.layer.isHidden = true
        Task_TopSpaceSections.constant = 0.   //your constraint of top view

点击这里查看https://www.youtube.com/watch?v=EBulMWMoFuw

正如no_scene建议的那样,您可以通过在运行时改变约束的优先级来实现这一点。这对我来说容易得多,因为我有不止一个需要移除的阻塞视图。

下面是使用ReactiveCocoa的代码片段:

RACSignal* isViewOneHiddenSignal = RACObserve(self.viewModel, isViewOneHidden);
RACSignal* isViewTwoHiddenSignal = RACObserve(self.viewModel, isViewTwoHidden);
RACSignal* isViewThreeHiddenSignal = RACObserve(self.viewModel, isViewThreeHidden);
RAC(self.viewOne, hidden) = isViewOneHiddenSignal;
RAC(self.viewTwo, hidden) = isViewTwoHiddenSignal;
RAC(self.viewThree, hidden) = isViewThreeHiddenSignal;

RAC(self.viewFourBottomConstraint, priority) = [[[[RACSignal
    combineLatest:@[isViewOneHiddenSignal,
                    isViewTwoHiddenSignal,
                    isViewThreeHiddenSignal]]
    and]
    distinctUntilChanged]
    map:^id(NSNumber* allAreHidden) {
        return [allAreHidden boolValue] ? @(780) : @(UILayoutPriorityDefaultHigh);
    }];

RACSignal* updateFramesSignal = [RACObserve(self.viewFourBottomConstraint, priority) distinctUntilChanged];
[updateFramesSignal
    subscribeNext:^(id x) {
        @strongify(self);
        [self.view setNeedsUpdateConstraints];
        [UIView animateWithDuration:0.3 animations:^{
            [self.view layoutIfNeeded];
        }];
    }];