将NSLayoutConstraint常量视为乘数?

时间:2015-04-02 01:07:31

标签: swift autolayout

我在容器UIView中有三个水平对齐的UIView。这三个视图应该跨越上面UIImageView的整个宽度。然而,问题是有时只应显示一个或两个子视图。

我设置了我的视图层次结构:

enter image description here

由于子视图设置为等于第一个子视图的宽度(将始终显示),我只需将第一个子视图的宽度设置为UIImageView宽度的一小部分。因此,如果应显示三个子视图,则第一个子视图的乘数将为UIImageView宽度的1/3。如果应显示两个子视图,则乘数将为1/2。如果只有一个,乘数将为1.

这似乎是一个完美的解决方案,但乘数属性是只读的。我第一次尝试解决这个问题的方法是在第一个子视图上创建三个不同的NSLayoutConstraint,所有这些都有不同的乘数,其中有两个被关闭。然后,在运行时,我会根据我想要显示的视图数量,使用适当的乘数启用适当的常量。

这导致了许多难看的错误,我的第二个解决方案也是如此:

var constraint = NSLayoutConstraint(item: color1, attribute:NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: imageView, attribute: NSLayoutAttribute.Width, multiplier: 1/2, constant: 0)
view.addConstraint(constraint)

我会根据我想要的乘数向视图添加新约束。当然,这导致了一个错误:

  

当添加到视图时,约束的项必须是该视图的后代(或视图本身)。如果在组装视图层次结构之前需要解析约束,则会崩溃。

我的问题因此,我是否可以将constant属性视为multiplier属性。但是,我这样做的恐惧是,如果我为第一个子视图的宽度设置constant,则在手机旋转时它不会更新其宽度。

对于所有这一切,是否有更好的解决方案?

1 个答案:

答案 0 :(得分:1)

首先,在您的问题中,您使用的是IB,但您似乎建议每次移动到视图控制器时可能会有不同数量的视图,这就是我决定以编程方式创建NSLayoutConstraint的原因。

其次,我的解决方案很好,前提是您在视图控制器上时无意更改视图数量。如果你这样做,那么这需要更多的工作。

在视图控制器中:

var viewWidthConstraints : [NSLayoutConstraint] = []

override func viewDidLoad() {
    super.viewDidLoad()

    let numberOfViews = 3
    var previousView: UIView = self.view

    for i in 0..<numberOfImages {
        let myView = UIView()
        myView.setTranslatesAutoresizingMaskIntoConstraints(false)
        myView.backgroundColor = UIColor.grayColor().colorWithAlphaComponent(CGFloat(i) * (1/CGFloat(numberOfImages)) + 0.1)
        self.view.addSubview(myView)

        let heightConstraint = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|",
                                options: .DirectionLeadingToTrailing,
                                metrics: nil,
                                views: ["view" : myView])

        let widthConstraint = NSLayoutConstraint(item: myView, 
                                attribute: .Width, 
                                relatedBy: .Equal, 
                                toItem: nil, 
                                attribute: .NotAnAttribute, 
                                multiplier: 1.0, 
                                constant: self.view.frame.width / CGFloat(numberOfImages))

        let attribute: NSLayoutAttribute = (i == 0) ? .Left : .Right
        let leftConstraint = NSLayoutConstraint(item: myView,
            attribute: .Left,
            relatedBy: .Equal,
            toItem: previousView,
            attribute: attribute,
            multiplier: 1.0,
            constant: 0.0)

        self.view.addConstraints(heightConstraint)
        self.view.addConstraint(leftConstraint)
        myView.addConstraint(widthConstraint)

        viewWidthConstraints.append(widthConstraint)

        previousView = myView
    }
}

func updateWidthConstraints() {
    if viewWidthConstraints.count > 0 {
        let width = self.view.frame.width / CGFloat(viewWidthConstraints.count)

        for constraint in viewWidthConstraints {
            constraint.constant = width
        }
    }
}

override func viewWillLayoutSubviews() {
    updateWidthConstraints()
}

viewDidLoad中,您将UIView添加到视图中并设置其约束。您可以更改垂直约束以使UIView显示在UIImageView下方。并更改numberOfViews以增加或减少观看次数。

然后在viewWillLayoutSubviews中使用宽度约束更新每个视图的宽度。这将确保,如果旋转设备,每个视图将占用正确的屏幕比例。

这是水平方向的样子。

enter image description here

垂直方向。

enter image description here