动态创建按钮的布局约束

时间:2015-05-09 23:16:09

标签: ios objective-c autolayout nslayoutconstraint

我正在尝试使用动态创建的按钮创建视图。我发现很难为内部对象设置约束,而不是创建第一个内部对象。这个问题在哪里?

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 个答案:

答案 0 :(得分: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;

等等。关键是:这就是我“增长我的代码”的方式,始终以简单和不断发展为起点,确保它在每次迭代中都有效,直到我达到我真正想要做的事情。你们也这样做!