动态数量的视图的自动布局

Posted

技术标签:

【中文标题】动态数量的视图的自动布局【英文标题】:AutoLayout for a Dynamic number of Views 【发布时间】:2014-01-09 15:47:35 【问题描述】:

我在UIViewController 的底部有一个UIView,可以添加不同数量的视图。

NSUInteger letterCount = [word length];

        NSLog(@"The word letter count is: %ld",(unsigned long)letterCount);

        for (int i = 0; i < letterCount; i++) 
            NSLog(@"new view being created");

            UIView *letterTileView = [UIView autolayoutView];
            letterTileView.tag = 600 + i;
            [self.bottomBarView addSubview:letterTileView];
        

单词可以是任何单词,因此有不同数量的字母。如果单词是 APPLE,它将在底部栏视图中创建 5 个子视图。

我想使用自动布局来布局这些视图。每个视图应为 48x48(高 x 宽)。我希望这些子视图在底部栏视图中居中并在它们之间有填充。

我之前使用以下方法设置 AL,但不确定如何处理动态情况并正确布局。

+ (NSArray *)constraintsWithVisualFormat:(NSString *)format  options:(NSLayoutFormatOptions)opts  metrics:(NSDictionary *)metrics  views:(NSDictionary *)views

【问题讨论】:

在代码中添加约束是一件常见且简单的事情。事实上,Apple 提供了示例代码来展示如何做到这一点(在与您描述的情况非常相似的情况下)。您到底遇到了什么问题? 你能分享他们提供的例子吗? Auto Layout 的文档实际上非常有限。我遇到的问题是我正在尝试布局动态数量的视图,例如 |-[view1]-[view2]-[view3]-|。但不确定如何在视图创建期间构建约束 观看关于自动布局的 WWDC 2012 视频以及与之相关的可下载代码。有一个游戏的字母砖排成一排,和你描述的非常相似。 【参考方案1】:

这是我书中的一个示例,我在其中以编程方式生成一堆 UILabel 并在执行过程中为它们添加约束。这与您的情况不同(我的标签是垂直排列的),但它显示了在动态创建界面时添加约束是多么容易:

UILabel* previousLab = nil;
for (int i=0; i<30; i++) 
    UILabel* lab = [UILabel new];
    // lab.backgroundColor = [UIColor redColor];
    lab.translatesAutoresizingMaskIntoConstraints = NO;
    lab.text = [NSString stringWithFormat:@"This is label %d", i+1];
    [v addSubview:lab];
    [v addConstraints:
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[lab]"
                                             options:0 metrics:nil
                                               views:@@"lab":lab]];
    if (!previousLab)  // first one, pin to top
        [v addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[lab]"
                                                 options:0 metrics:nil
                                                   views:@@"lab":lab]];
     else  // all others, pin to previous
        [v addConstraints: 
         [NSLayoutConstraint
          constraintsWithVisualFormat:@"V:[prev]-(10)-[lab]"
          options:0 metrics:nil
          views:@@"lab":lab, @"prev":previousLab]];
    
    previousLab = lab;

【讨论】:

谢谢@matt - 我能够使用与您上面的答案类似的方法。它还在 [previousView] 循环之后添加另一个约束到超级视图。感谢您的帮助 一直在寻找这样的解决方案。然而,我在一个视图中有一组字段(如带有标签和输入的表单)作为单行。所有其他行都将低于此值。非常感谢@matt【参考方案2】:

我过去所做的是根据您将拥有的视图数量动态创建可视格式字符串。一些示例代码:

NSArray *views = @[view1, view2, view3]; // this would be a dynamic array with views

NSMutableString *vflString = [NSMutableString string];
NSMutableDictionary *viewsDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < [views count]; i++) 
    NSString *viewIdentifier = [NSString stringWithFormat:@"view%d", i];
    [vflString appendString:[NSString stringWithFormat:@"-[%@]-", viewIdentifier];
    viewsDictionary[viewIdentifier] = views[i];


NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:vflString options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:constraints];

当然,您也可以更改指标和定位等。

【讨论】:

这对我不起作用,因为您将 viewIdentifier 传递给 vflString,但这只是一个创建的字符串,而不是指向视图的指针的实际名称。如何动态创建指向我的新视图的指针名称,以便在我的示例中正确传递名称? @StuartM 看看@Scott 向您展示了什么。 viewsDictionary 是指向新视图的“指针”。 @StuartM:指向视图的变量的实际名称无关紧要。在许多情况下,使用NSDictionaryMakeWithVariableBindings() 有助于使键和视图之间的链接变得容易,但您没有 使用它。

以上是关于动态数量的视图的自动布局的主要内容,如果未能解决你的问题,请参考以下文章

iOS:自动布局动态数量的项目

使用自动布局自定义集合视图单元格的动态高度

具有自动布局的多个动态视图

如何使用自动布局动态更改超级视图的高度

动态设置自动布局以在 iOS 中滚动视图

如何在自动布局中设置视图下方不同数量按钮的宽度