以编程方式自动布局不起作用

Posted

技术标签:

【中文标题】以编程方式自动布局不起作用【英文标题】:AutoLayout programmatically doesn't work 【发布时间】:2016-08-06 07:26:15 【问题描述】:

我想深入了解自动布局,所以我想以编程方式进行以便正确理解它。我知道如何通过故事板很好地使用它。现在这就是我正在做的事情(@987654321 @)

-(void)scenario2

    PGView *viewA = [[PGView alloc]initWithFrame:CGRectMake(100, 100, 100, 100) andBackgroundColor:[UIColor blackColor]];
    [self.view addSubview:viewA];

    PGView *viewB = [[PGView alloc]initWithFrame:CGRectMake(200, 300, 100, 100) andBackgroundColor:[UIColor yellowColor]];
    [self.view addSubview:viewB];

    viewA.translatesAutoresizingMaskIntoConstraints = NO;
    viewB.translatesAutoresizingMaskIntoConstraints = NO;

    NSLayoutConstraint *constraint;

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];

    //problem statement
    constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
    [self.view addConstraint:constraint];

    NSLog(@"%@",viewA);
    NSLog(@"%@",viewB);


    所以这里我初始化了两个不同颜色的视图。

    我知道我需要设置属性。 translatesAutoresizingMaskIntoConstraintsNO 在应用任何新约束之前。所以我做到了。

    现在我正在指定两个视图的高度和宽度。因此,两个视图的 x_position 和 y_position 都是 0。我运行代码并得到预期的结果。两个视图在点 (0,0) 处都有指定的高度和宽度。

问题

    现在当我写“问题陈述”语句来根据viewA的宽度调整viewB的宽度时,它不起作用。

    另外,当我打印视图 viewA 和 viewB 时,它会将帧打印为 (0,0,0,0)。

谁能解释一下这种行为?

编辑:这是我所做的一些修改。我已经使用“hasAmbiguousLayout”检查了两个视图的歧义,现在它工作正常。现在如果我想将 viewB 的宽度调整为三次,下一步应该是什么viewA 的宽度?

-(void)scenario2

PGView *viewA = [PGView new];
viewA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:viewA];

PGView *viewB = [PGView new];
viewB.backgroundColor = [UIColor blackColor];
[self.view addSubview:viewB];

viewA.translatesAutoresizingMaskIntoConstraints = NO;
viewB.translatesAutoresizingMaskIntoConstraints = NO;

NSLayoutConstraint *constraint;

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[viewB(==100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewB)]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[viewA(==200)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(viewA)]];


NSLog(@"%d",viewA.hasAmbiguousLayout);
NSLog(@"%d",viewB.hasAmbiguousLayout);

NSLog(@"%@",viewA);
NSLog(@"%@",viewB);


【问题讨论】:

【参考方案1】:

问题在于您已将 A 和 B 的宽度限制分别明确设置为 200 和 100。因此,当与其他约束结合时,指定一个宽度应为另一个宽度三倍的附加约束是不可满足的。

此外,约束是不明确的,因为您已经定义了宽度和高度约束,但还没有定义 where 两个框架应该在哪里。是的,您已经为这两个视图定义了 frame,但是在应用约束时会忽略它。您可能根本不应该定义 frame 值,因为它具有误导性和混淆性。但是您应该设置,例如,前导和顶部约束,或者在 VFL 中指定它们,或者添加centerXcenterY 约束。您只需要一些约束来指定视图的放置位置,并且有很多方法可以指定。

最后你没有看到合理的frame 值的原因是你已经定义了约束,但它们还没有被应用。如果您愿意,可以在viewDidLayoutSubviews 中检查它们。


你可能会这样做:

- (void)scenario2 

    PGView *viewA = [PGView new];
    viewA.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:viewA];

    PGView *viewB = [PGView new];
    viewB.backgroundColor = [UIColor blackColor];
    [self.view addSubview:viewB];

    viewA.translatesAutoresizingMaskIntoConstraints = NO;
    viewB.translatesAutoresizingMaskIntoConstraints = NO;

    NSDictionary *views = NSDictionaryOfVariableBindings(viewA, viewB);

    // note, I added `|-100-` to say it's 100 points from the top (and 100 tall)

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[viewB(==100)]" options:0 metrics:nil views:views]];

    // likewise, to say 200 points from the left (and 100 wide)

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-200-[viewB(==100)]" options:0 metrics:nil views:views]];

    // again, 100 from the top (as well as 200 tall)

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[viewA(==200)]" options:0 metrics:nil views:views]];

    // and 100 from the left
    // but I've removed width definition, as we'll use your multiplier constraint below

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[viewA]" options:0 metrics:nil views:views]];

    // now that we've removed the width constraint from the above,
    // this should now work fine

    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:viewA attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeWidth multiplier: 3.0f constant: 0.0f];
    [self.view addConstraint:constraint];

    // no point in doing this, because constraints haven't yet been applied
    //
    // NSLog(@"%@",viewA);
    // NSLog(@"%@",viewB);


// if you want to see where they are, you could do that here:

- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];

    for (UIView *view in self.view.subviews) 
        NSLog(@"%@", view);
    
    NSLog(@"-----");

【讨论】:

我已经更新了我的问题,对我的代码进行了一些修改。你能解释一下吗? @Reckoner - 好的,所以,就像我上面的代码 sn-p 一样,从 A 的 VFL 中删除宽度定义,然后您可以使用乘数约束。现在,我定义了前导和顶部约束(我从您尝试设置框架中推断出),您没有在编辑中使用它们,但希望这仍然足以说明我的观点。 不过我有一个问题......当我最后在我的代码中打印 viewA 和 viewB 时,为什么它将帧打印为 (0 0;0 0)?跨度>

以上是关于以编程方式自动布局不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用 UILabel 以编程方式自动布局不起作用

以编程方式更改视图尺寸时,自动布局似乎不起作用

以编程方式使用布局锚点的自动布局不起作用

以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用

自动布局:缩放填充不起作用

UIView addSubview 自动布局不起作用