使用视觉格式化语言计算不需要的按钮高度

Undesired button height being calculated using Visual Formatting Language

我有一个 UIViewController,上面有四个 UIButtons (2 x 2),我在界面生成器中布置得很好。我将拥有一个免费且支持广告的应用程序版本,因此我需要根据应用程序是付费版本还是广告支持版本重做该场景以进行加载。基于此,我正在尝试使用可视格式语言来布置视图。我的 UIButton 身高值不正确,尽管我在计算它们时考虑了它们。我想不通我的错误(或遗漏?)。

这是我的界面生成器的屏幕截图。

我对界面生成器中的按钮没有限制,但我确实有 IBOutlets 连接到 MyViewControllerMyViewController 在导航控制器中,底部有一个标签栏。

我创建了一个名为 layoutButtons 的方法,我在 super.viewDidLoad() 之后调用了 viewDidLoad。这是:

func layoutButtons() {
    // Configure layout constraints

    // Remove interface builder constraints from storyboard
    view.removeConstraints(view.constraints)

    // create array to dump constraints into
    var allConstraints = [NSLayoutConstraint]()

    // determine screen size
    let screenSize: CGRect = UIScreen.mainScreen().bounds

    let navBarRect = navigationController!.navigationBar.frame
    let navBarHeight = navBarRect.height

    let tabBarRect = tabBarController!.tabBar.frame
    let tabBarHeight: CGFloat = tabBarRect.height

    // calculate button width based on screen size

    // padding for left + middle + right = 8.0 + 8.0 + 8.0 = 24.0
    let buttonWidth = (screenSize.width - 24.0) / 2

    /*
    My buttons are extending under the top & bottom layout guides despite accounting
    for them when I set the buttonHeight.
    */

    // padding for top + middle + bottom = 8.0 + 8.0 + 8.0 = 24.0
    let buttonHeight = (screenSize.height - topLayoutGuide.length - bottomLayoutGuide.length - 24.0) / 2

    // create dictionary of metrics
    let metrics = ["buttonWidth": buttonWidth,
        "buttonHeight": buttonHeight,
        "navBarHeight": navBarHeight,
        "tabBarHeight": tabBarHeight,
        "bannerAdWidth": bannerAdWidth,
        "bannerAdHeight": bannerAdHeight]

    // create dictionary of views
    var views: [String : AnyObject] = ["firstButton": firstButton,
        "secondButton": secondButton,
        "thirdButton": thirdButton,
        "fourthButton": fourthButton,
        "topLayoutGuide": topLayoutGuide,
        "bottomLayoutGuide": bottomLayoutGuide]

    let topRowHorizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-[firstButton(buttonWidth)]-[secondButton(buttonWidth)]-|",
        options: [.AlignAllCenterY],
        metrics: metrics,
        views: views)
    allConstraints += topRowHorizontalConstraints

    let bottomRowHorizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-[thirdButton(buttonWidth)]-[fourthButton(buttonWidth)]-|",
        options: [.AlignAllCenterY],
        metrics: metrics,
        views: views)
    allConstraints += bottomRowHorizontalConstraints

    let leftColumnVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[topLayoutGuide]-[firstButton(buttonHeight)]-[thirdButton(buttonHeight)]-[bottomLayoutGuide]|",
        options: [],
        metrics: metrics,
        views: views)
    allConstraints += leftColumnVerticalConstraints

    let rightColumnVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[topLayoutGuide]-[secondButton(buttonHeight)]-[fourthButton(buttonHeight)]-[bottomLayoutGuide]|",
        options: [],
        metrics: metrics,
        views: views)
    allConstraints += rightColumnVerticalConstraints

    NSLayoutConstraint.activateConstraints(allConstraints)
}

我摆弄过我的 buttonHeight 变量,但我尝试的每次迭代都会导致按钮在 topLayoutGuidebottomLayoutGuide 下扩展。这是它在运行时的样子:

我欢迎任何关于在哪里查找我的错误的建议。感谢阅读。

我最初遵循 Ray Wenderlich's Visual Format Language tutorial 教程的设置与我的相似,因为 subViews 在故事板上并通过 IBOutlets 连接到 MyViewController

出于绝望,我修改了情节提要并在代码中创建了 UIButtons。一路上,我发现我的问题是我在布局之前在按钮上设置图像。 这个故事的寓意是,在 UIButtons 布局之前不要在 UIButtons 上设置图像!

下面是从我的 viewDidLoad 中的一个方法调用的代码,它布置了一个 2 x 2 的按钮网格:

    // Configure Buttons
    firstButton.translatesAutoresizingMaskIntoConstraints = false
    // code to customize button

    secondButton.translatesAutoresizingMaskIntoConstraints = false
    // code to customize button

    thirdButton.translatesAutoresizingMaskIntoConstraints = false
    // code to customize button

    fourthButton.translatesAutoresizingMaskIntoConstraints = false
    // code to customize button

    // Add buttons to the subview
    view.addSubview(firstButton)
    view.addSubview(secondButton)
    view.addSubview(thirdButton)
    view.addSubview(fourthButton)

    // create views dictionary
    var allConstraints = [NSLayoutConstraint]()

    let views: [String : AnyObject] = ["firstButton": firstButton,
        "secondButton": secondButton,
        "thirdButton": thirdButton,
        "fourthButton": fourthButton,
        "topLayoutGuide": topLayoutGuide,
        "bottomLayoutGuide": bottomLayoutGuide]

    // Calculate width and height of buttons
    // 24.0 = left padding + middle padding + right padding
    let buttonWidth = (screenSize.width - 24.0) / 2
    let buttonHeight = (screenSize.height - topLayoutGuide.length - bottomLayoutGuide.length - 24.0) / 2

    // Create a dictionary of metrics
    let metrics = ["buttonWidth": buttonWidth,
    "buttonHeight" : buttonHeight]

    let topVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[topLayoutGuide]-[firstButton(buttonHeight)]",
        options: [],
        metrics: metrics,
        views: views)
    allConstraints += topVerticalConstraints

    let topRowHorizontalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-[firstButton(buttonWidth)]-[secondButton(==firstButton)]-|",
        options: NSLayoutFormatOptions.AlignAllCenterY,
        metrics: metrics,
        views: views)
    allConstraints += topRowHorizontalConstraints

    let bottomRowHorizontalContraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "H:|-[thirdButton(buttonWidth)]-[fourthButton(==thirdButton)]-|",
        options: NSLayoutFormatOptions.AlignAllCenterY,
        metrics: metrics,
        views: views)
    allConstraints += bottomRowHorizontalContraints

    let leftColumnVerticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:[firstButton]-[thirdButton(==firstButton)]-[bottomLayoutGuide]-|",
        options: [],
        metrics: metrics,
        views: views)
    allConstraints += leftColumnVerticalConstraints

    let rightColumnVerticalConstriants = NSLayoutConstraint.constraintsWithVisualFormat(
        "V:[secondButton(buttonHeight)]-[fourthButton(==secondButton)]-[bottomLayoutGuide]-|",
        options: [],
        metrics: metrics,
        views: views)
    allConstraints += rightColumnVerticalConstriants

    NSLayoutConstraint.activateConstraints(allConstraints)

    // ** DON'T SET IMAGES ON THE BUTTONS UNTIL THE BUTTONS ARE LAID OUT!!!**
    firstButton.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
    firstButton.setImage(UIImage(named: "first.png"), forState: .Normal)

    secondButton.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
    secondButton.setImage(UIImage(named: "second.png"), forState: .Normal)

    thirdButton.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
    thirdButton.setImage(UIImage(named: "third.png"), forState: .Normal)

    fourthButton.imageView?.contentMode = UIViewContentMode.ScaleAspectFit
    fourthButton.setImage(UIImage(named: "fourth.png"), forState: .Normal)