swift2 以编程方式在Swift中实现尾随和前导约束(NSLayoutConstraints)

rsaldnfx  于 2022-11-06  发布在  Swift
关注(0)|答案(4)|浏览(192)

我从xib中添加一个视图到ViewController中,然后设置它的约束以实际适应它

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    ...
    ...
    view!.addSubview(gamePreview)
    gamePreview.translatesAutoresizingMaskIntoConstraints = false
    if #available(iOS 9.0, *) {
        // Pin the leading edge of myView to the margin's leading edge
        gamePreview.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
        //Pin the trailing edge of myView to the margin's trailing edge
        gamePreview.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true

    } else {
        // Fallback on earlier versions
        view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .TrailingMargin, relatedBy: .Equal, toItem: view, attribute: .TrailingMargin, multiplier: 1, constant: 0))

        view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .LeadingMargin, relatedBy: .Equal, toItem: view, attribute: .LeadingMargin, multiplier: 1, constant: 0))
    }
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}

我想做的是:为了实际适合我的视图,将其限制在ViewController视图的顶部、前导、尾随,并带有一个前缀高度。我添加到主视图的视图有它自己的透明背景视图,因此不需要边距(该视图是为了设备的宽度大小,因此)。
我已经放置了两对应该相等的行(在我的尝试中),带有if,因为if中的前两行实际上只在iOS9〉中可用,而我正在尝试在else语句中为每个设备(从iOS8开始)做同样的事情。
这是我得到的:
iOS9+在左边,iOS8+在右边。透明背景被涂成红色,以显示发生了什么(不介意在不同的高度的图像,他们在应用程序中是相同的高度,而不是看左边和右边增加的边距)

我也尝试了AutoLayoutDSL-Swift,但没有帮助,我不是它的Maven,但每一次尝试只会使事情变得更糟。
如何使用经典的NSLayoutConstraints方法编写这些约束,以及如何使用像AutoLayoutDSL这样的框架或它的分支以更好的方式编写所有这些约束?(或者另一种方法,尽管现在我主要关注官方库)

des4xlb0

des4xlb01#

您需要使用leadingtrailing属性,而不是leadingMargintrailingMargin属性:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    ...
    ...
    view!.addSubview(gamePreview)
    gamePreview.translatesAutoresizingMaskIntoConstraints = false

    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0))            
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0))

    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}
j2cgzkjk

j2cgzkjk2#

多亏了@Paulw11......这就是解决方案

view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0))     
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0))        
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))

此外,我设法重写它如下使用AutoLayoutDSL-Swift为任何人感兴趣

view => gamePreview.trailing == view.trailing
     => gamePreview.leading == view.leading
     => gamePreview.height == 131
     => gamePreview.top == view.top + self.navigationController!.navigationBar.bounds.height + UIApplication.sharedApplication().statusBarFrame.size.height

最后一行有点长,因为view.top指的是真正的视图顶部,而没有考虑statusBar和navigationBar高度添加的填充。它们可以被替换为常量,等待有人提出更优雅的解决方案。

tzdcorbm

tzdcorbm3#

SWIFT 4更新

stackView.translatesAutoresizingMaskIntoConstraints = false

stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: stackView, attribute: .trailing, multiplier: 1, constant: 0))
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: stackView, attribute: .leading, multiplier: 1, constant: 0))

stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: self.addLayoutGuide, attribute: .bottom, multiplier: 1, constant: 0))
stackView.addConstraint(NSLayoutConstraint(item: stackView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute,multiplier: 1, 
constant: 131))
5us2dqdw

5us2dqdw4#

为什么不使用约束激活?您可以这样做:

var anchors = [NSLayoutConstraint]()
    anchors.append(view.topAnchor.constraint(equalTo: gamePreview.topAnchor, constant: 0))
    anchors.append(view.leadingAnchor.constraint(equalTo: gamePreview.leadingAnchor, constant: 0))
    anchors.append(view.trailingAnchor.constraint(equalTo: gamePreview.trailingAnchor, constant: 0))
    anchors.append(view.heightAnchor.constraint(equalTo: gamePreview.heightAnchor, multiplier: 1, constant: 131))
    NSLayoutConstraint.activate(anchors)

这是另一个。希望它能有所帮助。你可以根据父/子交换viewgamePreview,或者你可以为你的约束创建一个通用的助手扩展。我在YouTuber Here提供的教程中找到了一个,并稍微修改了一下,使其接受前导/尾随,左/右约束。你也可以在下面添加safeLayoutGuide,这使得它更适合未来。就像这样:

func anchor(_ top: UIView? = nil, left: UIView? = nil, bottom: UIView? = nil, right: UIView? = nil, width: UIView? = nil, height: UIView? = nil, topConstant: CGFloat = 0, leftConstant: CGFloat = 0, bottomConstant: CGFloat = 0, rightConstant: CGFloat = 0, widthConstant: CGFloat = 0, heightConstant: CGFloat = 0, isForLeading: Bool = false) -> [NSLayoutConstraint] {
    translatesAutoresizingMaskIntoConstraints = false

    var anchors = [NSLayoutConstraint]()
    if #available(iOS 11.0, *) {
        if let top = top {
            anchors.append(topAnchor.constraint(equalTo: top.safeAreaLayoutGuide.topAnchor, constant: topConstant))
        }

        if let left = left {
            if isForLeading  {
                anchors.append(leadingAnchor.constraint(equalTo: left.safeAreaLayoutGuide.leadingAnchor, constant: leftConstant))
            } else {
                anchors.append(leftAnchor.constraint(equalTo: left.safeAreaLayoutGuide.leftAnchor, constant: leftConstant))
            }
        }

        if let bottom = bottom {
            anchors.append(bottomAnchor.constraint(equalTo: bottom.safeAreaLayoutGuide.bottomAnchor, constant: -bottomConstant))
        }

        if let right = right {
            if isForLeading  {
                anchors.append(trailingAnchor.constraint(equalTo: right.safeAreaLayoutGuide.leadingAnchor, constant: rightConstant))
            } else {
                anchors.append(rightAnchor.constraint(equalTo: right.safeAreaLayoutGuide.rightAnchor, constant: -rightConstant))
            }
        }
        if let width = width {
            anchors.append(widthAnchor.constraint(equalTo: width.safeAreaLayoutGuide.widthAnchor, multiplier: 1, constant: widthConstant))
        } else if widthConstant > 0 {
            anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
        }

        if let height = height {
            anchors.append(heightAnchor.constraint(equalTo: height.safeAreaLayoutGuide.heightAnchor, multiplier: 1, constant: widthConstant))
        } else if heightConstant > 0 {
            anchors.append(widthAnchor.constraint(equalToConstant: heightConstant))
        }
        anchors.forEach({$0.isActive = true})
    } else {
        if let top = top {
            anchors.append(topAnchor.constraint(equalTo: top.topAnchor, constant: topConstant))
        }

        if let left = left {
            if isForLeading  {
                anchors.append(leadingAnchor.constraint(equalTo: left.leadingAnchor, constant: leftConstant))
            } else {
                anchors.append(leftAnchor.constraint(equalTo: left.leftAnchor, constant: leftConstant))
            }
        }

        if let bottom = bottom {
            anchors.append(bottomAnchor.constraint(equalTo: bottom.bottomAnchor, constant: -bottomConstant))
        }

        if let right = right {
            if isForLeading  {
                anchors.append(trailingAnchor.constraint(equalTo: right.leadingAnchor, constant: rightConstant))
            } else {
                anchors.append(rightAnchor.constraint(equalTo: right.rightAnchor, constant: -rightConstant))
            }
        }

        if let width = width {
            anchors.append(widthAnchor.constraint(equalTo: width.widthAnchor, multiplier: 1, constant: widthConstant))
        } else if widthConstant > 0 {
            anchors.append(widthAnchor.constraint(equalToConstant: widthConstant))
        }

        if let height = height {
            anchors.append(heightAnchor.constraint(equalTo: height.heightAnchor, multiplier: 1, constant: widthConstant))
        } else if heightConstant > 0 {
            anchors.append(widthAnchor.constraint(equalToConstant: heightConstant))
        }
        anchors.forEach({$0.isActive = true})
    }

    return anchors
}

然后这样称呼它:

_ = view.anchor(gamePreview, left: gamePreview, right: gamePreview, height: gamePreview, heightConstant: 131, isForLeading: true)

相关问题