2016-07-15 29 views
0

我正在進入iOS編程,掌握了固定數量的項目或多或少的自動佈局。比方說,我們有一個標題UILabel,字幕UILabel,那麼約束的視覺格式是'V:|-[title]-10-[subtitle]-|'NSLayoutConstraint代碼中未知數量的子視圖

但是如果我根據某些API響應動態地創建子視圖會怎樣。例如,我需要添加40個子視圖。現在不再現實,我用視覺格式指定每個子視圖並跟蹤它們。什麼是正確的方法?

我想象一下,在添加每個子視圖之後,我會根據之前的視圖以constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:設置約束。這是要走的路嗎,還是有更好的辦法?

回答

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) 

我使用視覺格式化,但我做一個約束爲時間,我添加視圖(這正是你所問的)。

+0

哈。現在我感覺有點笨拙:)謝謝 – egze

+0

請注意,如果您希望滾動視圖將其contentSize.height設置爲實際允許滾動,您還需要將最後一個標籤限制在滾動視圖的底部。 –

+0

@robmayoff做到了這一點,粘貼時就切斷了 – matt

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

0

我構建了一個動態佈局引擎(水平佈局和垂直佈局)。

  1. 它接受一個視圖數組。

  2. 它將視圖作爲子視圖添加到容器中。

  3. 然後動態地組成一個垂直和水平的可視佈局字符串。 (它爲使用v%p佈局的每個視圖生成一個唯一的「Object Address」字符串。在viewDidLoad中調用:[myView addControls:@ [view1,view2,view3]],並且它將垂直放置它們爲你。
  4. 下面是垂直佈局的通用佈局引擎。請享用。

    @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]; 
    }