NSLayoutConstraint代码中未知数量的子视图

时间:2016-07-15 14:38:42

标签: ios

我正在进入iOS编程并且使用固定数量的项目或多或少地掌握了自动布局。比如,我们有一个UILabel用于标题,UILabel用于副标题,然后约束的可视格式为'V:|-[title]-10-[subtitle]-|'

但是,如果我根据某些API响应动态创建子视图,该怎么办?例如,我需要添加40个子视图。我用视觉格式指定每个子视图并跟踪它们是不现实的。什么是正确的方法?

我想在我添加的每个子视图之后,然后我使用constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:基于上一个视图设置约束。这是要走的路,还是有更好的方法?

3 个答案:

答案 0 :(得分:1)

  

我用视觉格式指定每个子视图并跟踪它们是不现实的

为什么不呢?你似乎认为这是某种“两种情况”。没有什么能阻止您使用可视化格式来构建约束集合。没有法律规定您必须将所有约束条件放入一个可视格式。

布局引擎不知道或关心您用于形成约束的符号。约束是约束!

考虑这段代码,我为滚动视图构建约束,并在其中包含30个标签:

    var con = [NSLayoutConstraint]()
    con.appendContentsOf(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|[sv]|",
            options:[], metrics:nil,
            views:["sv":sv]))
    con.appendContentsOf(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|[sv]|",
            options:[], metrics:nil,
            views:["sv":sv]))
    var previousLab : UILabel? = nil
    for i in 0 ..< 30 {
        let lab = UILabel()
        // lab.backgroundColor = UIColor.redColor()
        lab.translatesAutoresizingMaskIntoConstraints = false
        lab.text = "This is label \(i+1)"
        sv.addSubview(lab)
        con.appendContentsOf(
            NSLayoutConstraint.constraintsWithVisualFormat(
                "H:|-(10)-[lab]",
                options:[], metrics:nil,
                views:["lab":lab]))
        if previousLab == nil { // first one, pin to top
            con.appendContentsOf(
                NSLayoutConstraint.constraintsWithVisualFormat(
                    "V:|-(10)-[lab]",
                    options:[], metrics:nil,
                    views:["lab":lab]))
        } else { // all others, pin to previous
            con.appendContentsOf(
                NSLayoutConstraint.constraintsWithVisualFormat(
                    "V:[prev]-(10)-[lab]",
                    options:[], metrics:nil,
                    views:["lab":lab, "prev":previousLab!]))
        }
        previousLab = lab
    }
    con.appendContentsOf(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:[lab]-(10)-|",
            options:[], metrics:nil,
            views:["lab":previousLab!]))
    NSLayoutConstraint.activateConstraints(con)

我正在使用视觉格式,但我在添加视图时正在做一个约束(这正是你所询问的)。

答案 1 :(得分:0)

答案实际上取决于您想要的布局,因为有更高级别的工具可用于制作布局。

从iOS 9开始,您可以使用UIStackView来管理一行或一列视图。 By nesting stack views, you can easily make a grid of views.要了解UIStackView,请先查看“Mysteries of Auto Layout, Part 1” from WWDC 2015。如果您在代码中执行所有布局,则可以使用TZStackView,重新实现适用于iOS 7及更高版本的UIStackView

UICollectionView是在网格或许多其他安排中布置视图的另一种工具。它比UIStackView更复杂,但有很多介绍性材料可以教您如何使用它,例如“Introducing Collection Views” from WWDC 2012

答案 2 :(得分:0)

我构建了一个动态布局引擎(水平布局和垂直布局)。

  1. 它接受一系列视图。

  2. 它将视图作为子视图添加到容器中。

  3. 然后动态组合垂直和水平可视布局字符串。 (它为使用v%p布局的每个视图生成唯一的&#34;对象地址&#34;字符串。
  4. 只需在viewDidLoad中调用:[myView addControls:@ [view1,view2,view3]],它就会为你垂直排列。
  5. 这是垂直布局的通用布局引擎。享受。

    @implementation UIView (VerticalLayout)
    
    - (void)addControls:(NSArray*)controls
        align:(VerticalAlignment)alignment
        withHeight:(CGFloat)height
        verticalPadding:(CGFloat)verticalPadding
        horizontalPadding:(CGFloat)horizontalPadding
        topPadding:(CGFloat)topPadding
        bottomPadding:(CGFloat)bottomPadding
        withWidth:(CGFloat)width
    {
        NSMutableDictionary* bindings = [[NSMutableDictionary alloc] init];
        NSDictionary *metrics = @{
            @"topPadding": @(topPadding),
            @"bottomPadding": @(bottomPadding),
            @"verticalPadding": @(verticalPadding),
            @"horizontalPadding":@(horizontalPadding) };
    
        NSMutableString* verticalConstraint = [[NSMutableString alloc] initWithString:@"V:"];
        if (alignment == VerticalAlignTop || alignment == VerticalAlignStretchToFullHeight) {
            [verticalConstraint appendString:@"|"];
        }
    
        for (UIView* view in controls) {
            BOOL isFirstView = [controls firstObject] == view;
            BOOL isLastView = [controls lastObject] == view;
    
            [self addSubview: view];
    
            // Add to vertical constraint string
            NSString* viewName = [NSString stringWithFormat:@"v%p",view];
            [bindings setObject:view forKey:viewName];
    
            NSString* yLeadingPaddingString = @"";
            NSString* yTrailingPadding = @"";
            if (isFirstView && topPadding > 0) {
                yLeadingPaddingString = @"-topPadding-";
            }
            else if (!isFirstView && verticalPadding > 0) {
                yLeadingPaddingString = @"-verticalPadding-";
            }
    
            if (isLastView && bottomPadding > 0) {
                yTrailingPadding = @"-bottomPadding-";
            }
    
            [verticalConstraint appendFormat:@"%@[%@%@]%@",
                yLeadingPaddingString,
                viewName,
                height > 0 ? [NSString stringWithFormat:@"(%f)", height] : @"",
                yTrailingPadding];
    
            NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:
                    [NSString stringWithFormat: @"H:|-horizontalPadding-[%@%@]%@|",
                    viewName,
                    (width > 0 ? [NSString stringWithFormat:@"(%lf)", width] : @""),
                    width > 0 ? @"-" : @"-horizontalPadding-"]
                options:NSLayoutFormatDirectionLeadingToTrailing
                metrics:metrics
                views:bindings];
    
            // high priority, but not required.
            for (NSLayoutConstraint* constraint in constraints) {
                constraint.priority = 900;
            }
    
            // Add the horizontal constraint
            [self addConstraints: constraints];
        }
    
        if (alignment == VerticalAlignBottom || alignment == VerticalAlignStretchToFullHeight) {
            [verticalConstraint appendString:@"|"];
        }
    
        NSArray* constraints = [NSLayoutConstraint
                constraintsWithVisualFormat:verticalConstraint
                options:NSLayoutFormatAlignAllLeading
                metrics:metrics
                views:bindings];
        for (NSLayoutConstraint* constraint in constraints) {
            constraint.priority = 900;
        }
    
        // Add the vertical constraints for all these views.
        [self addConstraints:constraints];
    }