Autolayout“冲突的约束”

时间:2014-10-28 18:22:24

标签: ios objective-c autolayout nslayoutconstraint

我创建了一个自定义UIView,我使用它来模式显示UIToolbarUIPickerView。我试图让它变得非常可重用,所以我在代码中创建了所有UI,包括设置约束。

这是我用来设置视图以添加到另一个视图的方法体,然后将控件设置为从底部到视图的动画。

我的视图层次结构如下:

"Owner" view (view to which this view is added):<br>
    |-->"Background" view (set to the full size of "Owner", but mainly used as a dimmed background)<br>
        |-->"Container" view (view which holds the toolbar and picker)
            |--> Toolbar
            |--> Picker

这是我用来设置用户界面的代码:

- (void)prepareForView:(UIView *)view {
    UIView *containerView       = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
    [containerView setTranslatesAutoresizingMaskIntoConstraints:NO];
    self.containerView          = containerView;

    UIPickerView *picker        = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 162.0f)];
    [picker setTranslatesAutoresizingMaskIntoConstraints:NO];
    self.picker                 = picker;

    UIToolbar *toolbar          = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 44.0f)];
    [toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];

    UIBarButtonItem *done       = ...;
    UIBarButtonItem *flexSpace  = ...;
    UIBarButtonItem *cancel     = ...;
    toolbar.items               = @[done, flexSpace, cancel];

    [containerView addSubview:picker];
    [containerView addSubview:toolbar];

    [containerView addConstraints:[NSLayoutConstraint   constraintsWithVisualFormat:@"|[picker]|"                           options:NSLayoutFormatAlignAllBaseline  metrics:nil views:NSDictionaryOfVariableBindings(picker)]];
    [containerView addConstraints:[NSLayoutConstraint   constraintsWithVisualFormat:@"|[toolbar]|"                          options:NSLayoutFormatAlignAllBaseline  metrics:nil views:NSDictionaryOfVariableBindings(toolbar)]];
    [containerView addConstraints:[NSLayoutConstraint   constraintsWithVisualFormat:@"V:|[toolbar(==44)][picker(==162)]|"   options:NSLayoutFormatAlignAllLeading   metrics:nil views:NSDictionaryOfVariableBindings(toolbar, picker)]];

    [containerView layoutIfNeeded];

    [self addSubview:containerView];

    [self addConstraints:[NSLayoutConstraint            constraintsWithVisualFormat:@"|[containerView]|"                    options:NSLayoutFormatAlignAllBaseline  metrics:nil views:NSDictionaryOfVariableBindings(containerView)]];
    self.containerTop = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:self.frame.size.height];
    [self addConstraint:self.containerTop];

    [self layoutIfNeeded];

}

基本上,我希望containerView根据其内容(应该是静态的206分)来调整大小。然后,我在其超级视图的顶部和顶部之间设置了一个垂直空间约束(self)。后来,我动画更改,以便工具栏和选择器&#34;向上滑动&#34;在屏幕上。

这里是动画代码(错误始终在此之前触发):

// Add the view as a subview
[view addSubview:self];

// Setup view for display (here's what triggers the message)
[self prepareForView:view];

// Animate into view
[UIView animateWithDuration:animated?0.4f:0.0f
                 animations:^{
                     self.alpha = 1.0f;
                 }
                 completion:^(BOOL finished) {
                     // Now, slide the container view in from the bottom of the screen
                     self.containerTop.constant = self.frame.size.height - self.containerView.frame.size.height;
                     [UIView animateWithDuration:animated?0.4f:0.0f
                                      animations:^{
                                          [self layoutIfNeeded];
                                      }
                                      completion:^(BOOL finished) {
                                          if (postDisplay != nil) {
                                              postDisplay();
                                          }
                                      }
                      ];
                 }
 ];

目前正在测试的所有模拟器和设备上正确显示,但我讨厌有警告/错误,我担心这可能 NOT 在某些时候按需要工作。< / p>

以下是显示的实际错误消息(我非常确定每次都是完全相同的错误):

Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x170283430 V:|-(0)-[UIToolbar:0x137590850]   (Names: '|':UIView:0x170382b10 )>",
    "<NSLayoutConstraint:0x170283480 V:[UIToolbar:0x137590850(44)]>",
    "<NSLayoutConstraint:0x174084ba0 V:[UIToolbar:0x137590850]-(0)-[UIPickerView:0x137586100]>",
    "<NSLayoutConstraint:0x174081fe0 V:[UIPickerView:0x137586100(162)]>",
    "<NSLayoutConstraint:0x17409bbc0 V:[UIPickerView:0x137586100]-(0)-|   (Names: '|':UIView:0x170382b10 )>",
    "<NSLayoutConstraint:0x174095b80 V:[UIView:0x170382b10(736)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x174084ba0 V:[UIToolbar:0x137590850]-(0)-[UIPickerView:0x137586100]>

我不明白所有的约束都是预期的,然后显示的UI就是我想要的。当我在调试器中使用po [self.containerView recursiveDescription]检查视图的布局时,我发现框架正是我认为它们应该是的。我哪里错了?

1 个答案:

答案 0 :(得分:4)

&#34;容器&#34;视图似乎从下面一行的高度为736:
<NSLayoutConstraint:0x174095b80 V:[UIView:0x170382b10(736)]>

您已按如下方式列出了视图:
------ UIView的顶部-------(y = 0)
- 0空间 -
UIToolBar(y = 0到y = 44)
- 0空间 -
UIPickerView(y = 44到y = 206)***
- 0空间 -
------ UIView的底部-----(y = 736)

***这就是冲突所引发的地方。这距离UIView的底部不能有0个空间,所有其他约束都设置了它们的方式,或者UIView的高度不能与所有其他约束一样。




编辑:

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[containerView]|"                    options:NSLayoutFormatAlignAllBaseline metrics:nil views:NSDictionaryOfVariableBindings(containerView)]];

当你使用&#34; |&#34;在约束的visualFormat中,这是父视图。在这一行中你要说父视图在[containerView]的顶部有0个空格,而在[containerView]的底部也有0个空格。这使得容器视图与父级视图的高度相同。



编辑#2: 请看以下内容。我相信这与你想要完成的事情很接近。

[containerView addSubview:picker];
[containerView addSubview:toolbar];
[self addSubview:containerView];

// Height & Width for containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[containerView(%f)]", containerView.frame.size.height] options:nil metrics:nil views:@{@"containerView":containerView}]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:[containerView(%f)]", containerView.frame.size.width] options:nil metrics:nil views:@{@"containerView":containerView}]];

// Height & Width for picker
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[picker(%f)]", picker.frame.size.height] options:nil metrics:nil views:@{@"picker":picker}]];
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:[picker(%f)]", picker.frame.size.width] options:nil metrics:nil views:@{@"picker":picker}]];

// Height & Width for toolbar
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[toolbar(%f)]", toolbar.frame.size.height] options:nil metrics:nil views:@{@"toolbar":toolbar}]];
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:[toolbar(%f)]", toolbar.frame.size.width] options:nil metrics:nil views:@{@"toolbar":toolbar}]];

// Vertical Positioning of picker & toolbar in containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[picker]" options:nil metrics:nil views:@{@"picker":picker}]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[toolbar]-0-|" options:nil metrics:nil views:@{@"toolbar":toolbar}]];

// Horizontal Positioning of picker & toolbar in containerView
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:picker attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:toolbar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];

// Center containerView (X/Y) in parent (self)
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];



编辑#3:使用&#39;观看&#39;和&#39;指标&#39;字典。

NSDictionary *views = @{@"containerView":containerView, @"picker":picker, @"toolbar":toolbar};
NSDictionary *metrics = @{@"hCV":containerView.frame.size.height,
                          @"wCV":containerView.frame.size.width,
                          @"hP":picker.frame.size.height,
                          @"wP":picker.frame.size.width,
                          @"hT":toolbar.frame.size.height,
                          @"wT":toolbar.frame.size.width};

[containerView addSubview:picker];
[containerView addSubview:toolbar];
[self addSubview:containerView];

// Height & Width for containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[containerView(hCV)]" options:0 metrics:metrics views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[containerView(wCV)]" options:0 metrics:metrics views:views]];

// Height & Width for picker
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[picker(hP)]" options:0 metrics:metrics views:views]];
[picker addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[picker(wP)]" options:0 metrics:metrics views:views]];

// Height & Width for toolbar
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[toolbar(hT)]" options:0 metrics:metrics views:views]];
[toolbar addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[toolbar(wT)]" options:0 metrics:metrics views:views]];

// Vertical Positioning of picker & toolbar in containerView
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[picker]" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[toolbar]-0-|" options:0 metrics:nil views:views]];

// Horizontal Positioning of picker & toolbar in containerView
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:picker attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[containerView addConstraint:[NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:toolbar attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];

// Center containerView (X/Y) in parent (self)
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];