2014-10-28 3 views
0

Я создал пользовательский UIView, который я использую для отображения UIToolbar и UIPickerView. Я пытаюсь сделать его очень многоразовым, поэтому я создаю весь пользовательский интерфейс в коде, включая ограничения установки.Autolayout «конфликтующие ограничения»

Вот кусок метода, который я использую, чтобы установить представление для добавления в другое представление, а затем анимировать элементы управления вверх на вид снизу.

Мое мнение иерархия выглядит следующим образом:

"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). Позже я изменяю это так, чтобы панель инструментов и сборщик «скользнули вверх» на экран.

Вот код анимации (ошибка всегда срабатывает до этого момента):

// 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 работа по желанию в некоторой степени.

Вот фактическое сообщение об ошибке, отображаемый (я уверен, что это точно такая же ошибка каждый раз):

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]> 

То, что я не понимаю, что все ограничения, как ожидается, и то отображаемый интерфейс - это то, что я намерен. Когда я проверяю макет представления с po [self.containerView recursiveDescription] в отладчике, я вижу, что фреймы являются именно тем, что я думаю, что они должны быть. Где я иду не так?

ответ

4

Вид «Контейнер», как представляется, имеет высоту 736 от линии ниже:
<NSLayoutConstraint:0x174095b80 V:[UIView:0x170382b10(736)]>

Вы выложили вид, как показано ниже:
------ Верх UIView - ----- (у = 0)
- 0 Space -
UIToolbar (у = 0 у = 44)
- 0 Space -
UIPickerView (у = 44 у = 206) ***
- 0 Космос -
------ Нижняя часть UIView ----- (y = 736)

*** Здесь происходит конфликт. Это не может быть 0 в стороне от нижней части UIView со всеми другими ограничениями, установленными так, как они есть, или высота UIView не может быть тем, что есть со всеми другими ограничениями.




EDIT:

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

При использовании "|" в пределах видимогоФормата для ограничения это родительское представление.В этой строке вы говорите, что хотите, чтобы родительский вид находился в 0 в верхней части [containerView], а также в 0 пробел в нижней части [containerView]. Это позволяет контейнеру увидеть ту же высоту, что и родительский.



Edit # 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]]; 



Edit # 3: Использование 'взгляды' и словари 'показатели'.

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]]; 
+0

Хорошо, но почему это так? Я вижу, где он получает 736 из начального фрейма, который я установил, но разве это не просто отправная точка? Разве это не "исправлено", когда я называю '[self.containerView layoutIfNeeded]'? Как я могу «исправить» эту проблему? Может быть, просто «alloc» init] 'вид без рамки? – mbm29414

+0

Я попробовал 'alloc] init]' (который я понимаю, по сути, 'alloc] initWithFrame: CGRectZero]'), и он придумал ту же ошибку, за исключением того, что (736) был теперь (0). Поэтому, я думаю, я не понимаю, почему существует ограничение, связанное с высотой 'self.containerView' вообще. Откуда это происходит и как его удалить? – mbm29414

+0

Я обновил свой ответ так, надеюсь, что это поможет. – egarlock

Смежные вопросы