2015-05-09 2 views
-1

Я пытаюсь создать представление с динамически создаваемыми кнопками. Мне трудно установить ограничения для внутренних объектов, кроме первого, который был создан. Где проблема?Ограничения макета для динамически создаваемых кнопок

User Choices

Создать & Добавить кнопки для просмотра

-(void) createButton:(NSString *) btnText isButton:(BOOL) type phraseWidth:(NSInteger) width view:(UIView *) currentView { 
if (!type) { // if it's a button then create label & button at same place else only create button 
      // align left to prev button, align baseline 
    if (prevX == 5) { // button left aligned to rowView, right align none 
     UIButton *btnView = [[UIButton alloc] init]; 
     btnView.translatesAutoresizingMaskIntoConstraints=NO; 
     [currentView addSubview:btnView]; 
     NSDictionary *dictScrollConst = NSDictionaryOfVariableBindings(btnView); 
     NSString *hConstraint = [NSString stringWithFormat:@"H:|-%f-[btnView]|",prevX]; 
     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:hConstraint options:0 metrics:nil views:dictScrollConst]]; 
     NSString *vConstraint = @"V:|[btnView]|"; 
     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vConstraint options:0 metrics:nil views:dictScrollConst]]; 
     prevObject = btnView; 

    } 
    else { // align new button to previous button 
     UIButton *btnView = [[UIButton alloc] init]; 
     btnView.translatesAutoresizingMaskIntoConstraints=NO; 
     [currentView addSubview:btnView]; 
     NSDictionary *dictScrollConst = NSDictionaryOfVariableBindings(prevObject,btnView); 
     NSString *hConstraint = [NSString stringWithFormat:@"H:[prevObject]-%d-[btnView]",kHorizontalSidePadding]; 
     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:hConstraint options:0 metrics:nil views:dictScrollConst]]; 
     NSString *vConstraint = @"V:|[btnView]|"; 
     [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vConstraint options:0 metrics:nil views:dictScrollConst]]; 

    } 

    } 
} 

Не допускает ограничение быть добавлены относительно предыдущей кнопки, созданной. Подбрасывает исключение:

Невозможно создать макет с видом иерархии неподготовленной для ограничения

+1

Вы спрашиваете слишком много сразу. Разбейте это на _one_ проблему и спросите об этом, пожалуйста. Никто не хочет исправлять 50 строк кода для вас. – matt

+0

Спасибо за помощь в этом, я удалил блок, который не является частью проблемы. Надеюсь, это поможет другим понять проблему сейчас. – nirvana74v

ответ

3

Там еще слишком много кода для меня, чтобы выяснить, что происходит, но это гораздо очевидна:

NSString *vConstraint = @"V:|[btnView]|"; 
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vConstraint options:0 metrics:nil views:dictScrollConst]]; 
    [currentView addSubview:btnView]; 

Эти строки находятся в неправильном порядке. Вы не можете добавить ограничение, связанное с представлением (здесь, btnView) в то время, когда это представление отсутствует в иерархии представлений. (Это именно то, что сообщение об ошибке говорит вам, хотя оно дало ему фразы по довольно условной терминологии.)

Итак, добавьте подвью. Затем добавьте ограничение, которое влияет на него.


То, что я предлагаю вам сделать то, что я всегда делать: начать очень простой и работать ваш путь до полной степени актуальной проблемы. Итак, я предлагаю в качестве упражнения, которое вы начинаете со второй строки вашего макета, и посмотрите, можете ли вы сделать это простое упражнение: учитывая массив титров @[@"Yellow", @"Purple", @"Blue", @"Red"], можете ли вы использовать его для создания четырех кнопок по горизонтали?

мой код для этого. Обратите внимание, насколько ясен и прост - беспощадно логичный, запасной и простой. Мы всегда можем добавить твики позже, но это своего рода простотой вам нужно стараться поддерживать и развивать, так что вы не путайте себя:

NSArray* titles = @[@"Yellow", @"Purple", @"Blue", @"Red"]; 
UIView* previousButton = nil; 
for (NSInteger i = 0; i < 4; i++) { 
    UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem]; 
    [b setTitle:titles[i] forState:UIControlStateNormal]; 
    [b setTranslatesAutoresizingMaskIntoConstraints:NO]; 
    [self.view addSubview:b]; 
    [self.view addConstraints: 
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(100)-[b]" 
     options:0 metrics:nil views:@{@"b":b}]]; 
    if (i == 0) { 
     [self.view addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(50)-[b]" 
      options:0 metrics:nil views:@{@"b":b}]]; 
    } else { 
     [self.view addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:[p]-(20)-[b]" 
      options:0 metrics:nil views:@{@"b":b, @"p":previousButton}]]; 
    } 
    previousButton = b; 
} 

Учитывая это, мы сразу видим, один из что-то не так с вашим кодом: нет никаких доказательств того, что вы устанавливаете предыдущую кнопку (ваш prevObject) на любом, кроме первого прохода, когда, конечно, вам нужно сделать это на каждые.

Как только у нас есть код, который работает, мы можем начать его модифицировать, чтобы подойти к тому, что вы хотите сделать. Например, теперь легко изменить размер жесткого кодирования для использования таких переменных, как ваши:

NSArray* titles = @[@"Yellow", @"Purple", @"Blue", @"Red"]; 
UIView* previousButton = nil; 
NSInteger initialX = 5; // * 
NSInteger horizSpace = 10; // * 
for (NSInteger i = 0; i < 4; i++) { 
    UIButton* b = [UIButton buttonWithType:UIButtonTypeSystem]; 
    [b setTitle:titles[i] forState:UIControlStateNormal]; 
    [b setTranslatesAutoresizingMaskIntoConstraints:NO]; 
    [self.view addSubview:b]; 
    [self.view addConstraints: 
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(100)-[b]" 
     options:0 metrics:nil views:@{@"b":b}]]; 
    if (i == 0) { 
     [self.view addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(initialX)-[b]" 
      options:0 metrics:@{@"initialX":@(initialX)} views:@{@"b":b}]]; 
    } else { 
     [self.view addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:[p]-(horizSpace)-[b]" 
      options:0 metrics:@{@"horizSpace":@(horizSpace)} views:@{@"b":b, @"p":previousButton}]]; 
    } 
    previousButton = b; 

И так далее. Дело в том, что так я «вырастаю свой код», начиная всегда с простого и развивающегося, убедившись, что он работает на каждой итерации, пока я не дойду до того, что я действительно пытаюсь сделать. Идите и делайте то же самое!

+0

Я удалил беспорядок. Изменения, которые вы упомянули, все равно вызывают такую ​​же ошибку. – nirvana74v

+0

Могу ли я спросить, что вы думаете, что это должно делать: '" H: | -% f- [btnView] | "' Что это за «% f»? - О, я вижу. Послушайте, это может не иметь ничего общего с этим, но это не то, как вы вставляете числа в визуальный формат. Используйте словарь показателей; для чего он нужен. – matt

+0

Извините, я до сих пор смущен. Что такое 'prevX' и' prevObject'? И как мы знаем, что все происходит в том порядке, в котором вы ожидаете? – matt