使用自动布局调整同级视图的大小时,使用子视图重新定位 UIView 不起作用

Posted

技术标签:

【中文标题】使用自动布局调整同级视图的大小时,使用子视图重新定位 UIView 不起作用【英文标题】:Reposition of UIView with subviews not working when resizing a sibling view with auto layout 【发布时间】:2014-09-08 07:58:15 【问题描述】:

我有两个视图正在尝试使用自动布局调整大小/重新定位。

我设置了以下约束:

红色视图:

要查看的顶部空间:0 superview 的尾随和前导空格:0 高度等于:100

蓝色视图:

红色视图的顶部空间:0 superview 的尾随和前导空格:0 高度等于:100

两个视图都是self.view 的子视图。蓝色视图有一个UILabel 作为子视图(屏幕截图中未显示)。 我想要做的是改变红色视图的大小(带动画)并让蓝色视图跟随大小变化:

- (IBAction)resizeButtonPressed:(UIButton*)sender

    [UIView animateWithDuration:0.25 animations:^
        if (sender.selected) 
            self.redViewHeightConstraint.constant = 100; // collapse
        
        else 
            self.redViewHeightConstraint.constant = 200; // expand
        
        [self.view layoutIfNeeded];
    ];

    sender.selected = !sender.selected;

动画有效,红色视图的大小发生变化。然而,蓝色视图永远不会改变位置,即使它对红色视图的底部有限制。

我尝试添加[self.blueView layoutIfNeeded],甚至同时添加[self.view setNeedsUpdateConstraints][self.blueView setNeedsUpdateConstraints],但没有任何区别。

奇怪的是,如果我从蓝色视图中删除标签,一切都会按预期工作。一旦我再次添加它,蓝色视图就会保持静止。标签是否有任何约束都没有关系。

【问题讨论】:

【参考方案1】:

这是一个完整的实现:

@interface ViewController ()

@property(nonatomic, strong) NSLayoutConstraint* redViewHeightConstraint;

@end

@implementation ViewController


-  (void)viewDidLoad

    [super viewDidLoad];

    UIView* redView = [[UIView alloc] init];
    UIView* blueView = [[UIView alloc] init];

    redView.translatesAutoresizingMaskIntoConstraints = NO;
    blueView.translatesAutoresizingMaskIntoConstraints = NO;

    redView.backgroundColor = [UIColor redColor];
    blueView.backgroundColor = [UIColor blueColor];

    NSDictionary* views = NSDictionaryOfVariableBindings(redView, blueView);

    [self.view addSubview:redView];
    [self.view addSubview:blueView];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[redView]|"
                                                                      options:0
                                                                      metrics:nil
                                                                        views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[blueView]|"
                                                                      options:0
                                                                      metrics:nil
                                                                        views:views]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:redView
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeTop
                                                         multiplier:1
                                                           constant:0]];

    self.redViewHeightConstraint = [NSLayoutConstraint constraintWithItem:redView
                                                                attribute:NSLayoutAttributeHeight
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:nil
                                                                attribute:NSLayoutAttributeNotAnAttribute
                                                               multiplier:0
                                                                 constant:100];

    [self.view addConstraint:self.redViewHeightConstraint];


    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:blueView
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:redView
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1
                                                           constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:blueView
                                                          attribute:NSLayoutAttributeHeight
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:nil
                                                          attribute:NSLayoutAttributeNotAnAttribute
                                                         multiplier:0
                                                           constant:100]];

    UILabel* label = [[UILabel alloc] init];
    label.text = @"label";
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [blueView addSubview:label];

    [blueView addConstraint:[NSLayoutConstraint constraintWithItem:label
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:blueView
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1
                                                           constant:0]];

    [blueView addConstraint:[NSLayoutConstraint constraintWithItem:label
                                                         attribute:NSLayoutAttributeCenterY
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:blueView
                                                         attribute:NSLayoutAttributeCenterY
                                                        multiplier:1
                                                          constant:0]];

    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button addTarget:self
               action:@selector(resizeButtonPressed:)
     forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Expand" forState:UIControlStateNormal];
    [button setTitle:@"Collapse" forState:UIControlStateSelected];
    button.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:button];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                          attribute:NSLayoutAttributeTop
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:blueView
                                                          attribute:NSLayoutAttributeBottom
                                                         multiplier:1
                                                           constant:30]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1
                                                           constant:0]];





- (IBAction)resizeButtonPressed:(UIButton*)sender

    [UIView animateWithDuration:0.25 animations:^
        if (sender.selected) 
            self.redViewHeightConstraint.constant = 100; // collapse
        
        else 
            self.redViewHeightConstraint.constant = 200; // expand
        
        [self.view layoutIfNeeded];
    ];

    sender.selected = !sender.selected;


@end

【讨论】:

【参考方案2】:

我也遇到了同样的问题。 我通过在动画块(CGRect frame = self.label.frame;)之前保存标签的帧并在动画块中再次设置标签的帧(self.label.frame = frame;)来解决它

【讨论】:

我真的很想避免操纵框架,因为在使用自动布局时我们不应该这样做。此外,我想在这里了解我的问题的原因。 如何在blueView上添加标签?你添加了什么约束?

以上是关于使用自动布局调整同级视图的大小时,使用子视图重新定位 UIView 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用自动布局删除和重新添加子视图

(自动布局)容器视图调整大小但子视图不

父 UIViewController 调整容器视图大小时,子视图控制器不自动布局

如何使用自动布局调整视图大小以适合标签子视图?

使用自动布局调整子视图的大小

根据最大的子视图使用自动布局调整超级视图的大小