如何垂直自动布局UIViews列表,一个在另一个上面?

时间:2016-05-30 04:59:51

标签: ios swift autolayout

let N = 4 
let holder = UIView(frame: CGRectMake(0, 0, someWidth, N * 100))
for var i = 0; i <= N; i++ {
    let content = UIView(frame: CGRect.zero) //height should be 100
    content.backgroundColor = randomColor()
    content.translatesAutoresizingMaskIntoConstraints = true
    holder.addSubview(content)
}

上面的代码会将 N UIViews添加到holder。我想以编程方式使用NSLayoutConstraints垂直显示内容,一个在另一个上面。

每个内容的高度应为100.每个内容都应对所有4个边缘都有约束。第一个内容应该具有holder的top / leading / trailing约束(constant = 0)。最后一个内容应该有底部/前导/尾随约束(常量= 0)到holder

其他内容应该对其他兄弟内容有最高/最低限制(常数= 8)。

如何创建这些约束?

3 个答案:

答案 0 :(得分:1)

你可以做点什么,

   let content = UIView()
    content.backgroundColor = UIColor.redColor()
    content.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(content)


    let topConstraint = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
    view.addConstraint(topConstraint)

    let leadingConstraint = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
    view.addConstraint(leadingConstraint)

    let bottomConstraint = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    view.addConstraint(bottomConstraint)

 let trailingConstraint = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
    view.addConstraint(trailingConstraint)        

    let heightConstraint = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 100)
    view.addConstraint(heightConstraint)

在这里,您应该考虑holder而不是view

此约束适用于中间视图。对于第一个和最后一个视图场景应该是不同的,例如,

  //Top constraint for first view should be like,

   let topConstraintForfirstView = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    view.addConstraint(topConstraintForfirstView)

  //Bottom constraint for last view should be like,

   let bottomConstraintForLastview = NSLayoutConstraint(item: content, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
    view.addConstraint(bottomConstraintForLastview)

您可以通过更改约束的constant来管理空间或距离。如果你想在视图之间有20像素的垂直间距,那么你的常量为top constraints should be 20

您可以参考this answer作为参考。

不要给出高度和底部。如果你给出固定高度,那么你不需要底部,如果你给底部,那么你不需要修复高度。

希望这会有所帮助:)

答案 1 :(得分:1)

Vertical page

我为横向页面所做的一切。所以这是代码

var scrollView = UIScrollView()
var contectView = UIView();

添加holderview的子视图

    self.scrollView.translatesAutoresizingMaskIntoConstraints = false;
    self.view.addSubview(self.scrollView);

    self.contectView.translatesAutoresizingMaskIntoConstraints = false;
    self.scrollView.addSubview(self.contectView);

为holderView创建约束

 let views = ["contectView" : self.contectView , "scrollview" : self.scrollView ];

    // create constraint for scrollview
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollview]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))

    // create constraint for contectview with low priority for width and height
    self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[contectView(==scrollview@250)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
    self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[contectView(==scrollview@250)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))

制作水平字符串约束

     var verticalConstraintsFormat = "";  // create horizantal constraint string
    let subViews = NSMutableDictionary();
    subViews["scrollView"] = self.scrollView;

创建动态页面

 let totalPage : NSInteger = 10;

    for i in 0...totalPage {

        // Create your page here
        let objProductView  = UIView()
        objProductView.translatesAutoresizingMaskIntoConstraints = false;
        objProductView.backgroundColor = UIColor(white: CGFloat(arc4random()%100)/CGFloat(100), alpha: 1)
        self.contectView.addSubview(objProductView);

        let key = NSString(format: "productView%d", i) as  NSString
        subViews[key] = objProductView;


        if(i==0){
            verticalConstraintsFormat = verticalConstraintsFormat.stringByAppendingFormat("V:|-0-[%@(==100)]", key);
        }
        else if (i==totalPage) {
            verticalConstraintsFormat = verticalConstraintsFormat.stringByAppendingFormat("-0-[%@(==100)]-0-|", key);

        }
        else{
            verticalConstraintsFormat = verticalConstraintsFormat.stringByAppendingFormat("-0-[%@(==100)]", key);

        }

        let verticalConstraintsFormat1 = NSString(format:"H:|[%@(==scrollView)]", key);
        self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(verticalConstraintsFormat1 as String, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: subViews as AnyObject as! [String : AnyObject]));


    }
    self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(verticalConstraintsFormat as String, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: subViews as AnyObject as! [String : AnyObject]));

希望这有帮助。

答案 2 :(得分:1)

在我们的项目中,我们遇到了类似的问题,我们不得不使用以编程方式添加的约束向滚动视图的内容视图添加大量视图。为每个视图编写约束不仅使视图控制器变得臃肿,而且还是静态的。要添加另一个视图,我们必须再次编写约束。

我们最终创建了UIView的子类,现在为我们管理了这个。我们将此命名为NNVerticalStackView.h.m

这个课程的要点是以下方法。

-(void)addView:(UIView *)view
     belowView:(UIView *)viewAbove
     aboveView:(UIView *)viewBelow
    withHeight:(CGFloat)height{

    view.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:view];

    if(height != NNStackViewContentHeightMetric && height > 0) {
        NSArray * heightConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[view(height)]" options:0 metrics:@{@"height":@(height)} views:NSDictionaryOfVariableBindings(view)];
        [view addConstraint:heightConstraint.firstObject];
    }

    NSArray * defaultConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)];
    NSLayoutConstraint * upperConstraint,* lowerConstraint;

    if(viewAbove==self) {
        [self removeConstraint:_topConstraint];
        upperConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[view]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)].firstObject;
        _topConstraint = upperConstraint;
    }
    else
        upperConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[viewAbove]-0-[view]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view,viewAbove)].firstObject;

    if(viewBelow==self) {
        [self removeConstraint:_bottomConstraint];
        lowerConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[view]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)].firstObject;
        _bottomConstraint = lowerConstraint;
    }
    else
        lowerConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[view]-0-[viewBelow]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view,viewBelow)].firstObject;

    [self addConstraints:defaultConstraints];
    [self addConstraints:@[upperConstraint,lowerConstraint]];
}

对于最顶层的视图,viewAbove是容器视图(即self),否则它代表正在添加的视图上方的视图。 对于最底层的视图,viewBelow是容器视图,其他方面是添加当前视图下方的视图。

因此,对于这个子类,您打算做的事情可以很容易地编码为。

let N = 4
let holder = NNVerticalStackView(frame: CGRectMake(0, 0, someWidth, CGFloat(N) * 100.0))
for _ in 0...N {
    let content = UIView(frame: CGRect.zero) //height should be 100
    holder.insertStackItem(content, atIndex: 0, withItemHeight: 100.0)
}

对于偏移,您可能需要更改自定义类以定义自己的偏移量。