Autolayout约束不会因为爱或金钱而更新

时间:2015-07-13 17:15:47

标签: ios autolayout

我在自定义类中有一个方法,可以调整和约束自定义UIView:

-(void) sizeAndConstrainHeaderView:(HeaderView *)headerView inView:(UIView *)view {

    CGFloat height;
    // code to calculate height is omitted.

    headerView.heightConstraint = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];

    headerView.translatesAutoresizingMaskIntoConstraints = NO;

    if (!headerView.isConstrained) {
        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:view.frame.size.width]];
        [headerView addConstraint:headerView.heightConstraint];
        headerView.isConstrained = YES;
    }

    headerView.heightConstraint.constant = height;
    // trying everything here to get the constraint to update
    [headerView setNeedsUpdateConstraints];
    [headerView layoutIfNeeded];
    [view setNeedsUpdateConstraints];
    [view layoutIfNeeded];

    NSLog(@"height constraint constant: %f", headerView.heightConstraint.constant);

}

我在视图控制器中这样称呼它:

[customClass sizeAndConstrainHeaderView:_headerView inView:self.view];

由于多次调用(在检索数据之前,一次之后),因此存在是否添加约束的标志。然后,无论如何,高度常数被设置为计算的高度。但无论我怎么称呼,在视图或自定义视图中,视图的高度都不会改变,我无法弄清楚原因。其他限制工作正常。日志显示高度已更改。但这种观点并没有反映出来。我确实知道,因为我调试了视图层次结构并且可以看到它没有更新。

3 个答案:

答案 0 :(得分:1)

你说

  

由于多次调用(在检索数据之前,一次之后),因此存在是否添加约束的标志。

但是您的方法是在每次调用上执行此操作:

headerView.heightConstraint = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];

因此,在每次调用时,您都会创建一个新约束,将其存储在headerView.heightConstraint中,并将新约束设置为常量。

但是,您只在第一次调用方法时安装此新约束。

也许您应该只在第一次调用时创建约束:

-(void) sizeAndConstrainHeaderView:(HeaderView *)headerView inView:(UIView *)view {

    CGFloat height;
    // code to calculate height is omitted.

    if (!headerView.isConstrained) {
        headerView.translatesAutoresizingMaskIntoConstraints = NO;

        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
        [view addConstraint:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:view.frame.size.width]];

        headerView.heightConstraint = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:height];

        [headerView addConstraint:headerView.heightConstraint];
        headerView.isConstrained = YES;
    }

    headerView.heightConstraint.constant = height;
}

答案 1 :(得分:0)

这里可能存在很多问题,因为Autolayout是一件复杂的事情。但是我会立即通过您对高度约束的初步声明来解决问题。你声明了CGFloat的高度 - 但你没有给它一个值。然后将其设置为headerView的height约束属性的常量。所以看起来你把0作为一个常量,可能会使约束变得无用。

您是否在视图中使用笔尖或故事板?如果是这样,您可以使用IBOutlet将要影响的约束直接拖到视图类中。这是在运行时以编程方式更改约束常量的最常用方法。只需将其作为类属性拖放,然后像这样更改它的.constant值。

另一个问题可能是超级视图中的其他限制因素与此问题发生冲突,而Autolayout已经决定优先考虑另一个限制因素。如果存在与约束的冲突,您将获得有关它的大量日志消息,因此请密切注意这些。

以下是我通常的程序化约束,工作正常:

NSMutableArray *constraints = [NSMutableArray array];
NSString *verticalConstraint = [NSString stringWithFormat:@"V:|-%i-[headerView(%i)]-%i-|", topBuffer, height, bottomBuffer];
NSString *horizontalConstraint = [NSString stringWithFormat:@"H:|-%i-[headerView(%i)]-%i-", leading, width, trailing];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:verticalConstraint options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView)]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:horizontalConstraint options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView)]];
[self addConstraints:constraints];

答案 2 :(得分:0)

每当我使用这些调用时,我都不会将nil作为toItem参数传递。传递nil意味着约束与任何事物无关,这使得任何高度/宽度计算都无意义。警告:我通常不使用constraintWithItem调用,尽可能更容易使用visualFormat api。