简体   繁体   中英

AutoLayout constraints for programmatically added buttons in a scrollView

I'm struggling with making autolayout work for a horizontal scrollview populated with an unknown number of buttons (in this case the number is stored in sceneCount). I've tried to approach the problem in other ways as well, but this seems to be the closest I could get to a result (no contradictory constraints). Unfortunately I only get a white screen at runtime with no errors. This is how I wish my scrollView would look like. Hope you guys can spot the problem!

import UIKit

class ViewController: UIViewController {

let sceneCount = 4
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
var buttons: [UIButton] = [UIButton]()


func makeLayout(){

    //Make the content view
    let view1 = UIScrollView()
    view1.setTranslatesAutoresizingMaskIntoConstraints(false)
    view1.backgroundColor = UIColor.redColor()

    //Make the scroll view
    let view2 = UIScrollView()
    view2.setTranslatesAutoresizingMaskIntoConstraints(false)
    view2.backgroundColor = UIColor(red: 0.75, green: 0.75, blue: 0.1, alpha: 1.0)

    view.addSubview(view1)
    view2.addSubview(view1)

    //Create the buttons
    for i in 0...(sceneCount-1) {
        button.setTranslatesAutoresizingMaskIntoConstraints(false)
        button.addTarget(self, action: Selector("scene\(i)Pressed"), forControlEvents: UIControlEvents.TouchUpInside)
        button.setBackgroundImage(UIImage(named: "Scene\(i+1)"), forState: UIControlState.Normal)
        button.sizeThatFits(CGSizeMake(40, 40))

        buttons.append(button)
        view1.addSubview(button)

    }

    //set horizontal spacing between the buttons
    for i in 1...(sceneCount-2) {
        var button1 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
        var button2 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
        button1 = buttons[i - 1]
        button2 = buttons[i]
        var dictionary1 = [String: UIButton]()
        dictionary1.updateValue(button1, forKey: "scene1")
        dictionary1.updateValue(button2, forKey: "scene2")

        view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[scene1]-[scene2]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary1) as [AnyObject])
    }

    //set vertical spacing for all buttons
    for i in 0...(sceneCount-1) {
        var button1 = UIButton.buttonWithType(UIButtonType.System) as! UIButton
        button1 = buttons[i]
        var dictionary2 = [String: UIButton]()
        dictionary2.updateValue(button1, forKey: "button1")

        view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[button1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary2) as [AnyObject])
    }

    //set horizontal distance to container for first button
    if sceneCount > 0 {
        var buttonFirst: UIButton = buttons[0]
        var dictionary3 = [String: UIButton]()
        dictionary3.updateValue(buttonFirst, forKey: "buttonFirst")
        view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[buttonFirst]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary3) as [AnyObject])
    }

    //set horizontal distance to container for last button
    if sceneCount > 0 {
        var buttonLast: UIButton = buttons[sceneCount-1]
        var dictionary4 = [String: UIButton]()
        dictionary4.updateValue(buttonLast, forKey: "buttonLast")
        view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[buttonLast]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary4) as [AnyObject])
    }

}

override func viewDidLoad() {
    super.viewDidLoad()
    makeLayout()
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

}

I managed to make your code work with three major changes as follows:

1 - Your content view needs to be of type UIView

let view1 = UIView()

This view will hold a UIScrollView (view2) and they have to have their constraints set. On view1 you will be able to set the size of the scroll view, that's why I made view 2 with 0 distance from the super view.

view1.addSubview(view2)

var dictionary = [String: UIView]()
dictionary.updateValue(view1, forKey: "view1")
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])

dictionary = [String: UIView]()
dictionary.updateValue(view2, forKey: "view2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])

2 - As you were using the same reference to create new buttons, the final array would have the same button in every position. I moved the initialization of each button inside the for that creates buttons.

var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
view2.addSubview(button)

3- After that I just updated your constraints to be inserted between the buttons and the scroll view (view2).

And here is the final code:

import UIKit

class ViewController: UIViewController {

let sceneCount = 4
var buttons: [UIButton] = [UIButton]()

func makeLayout(){

    //Make the content view
    let view1 = UIView()
    view1.setTranslatesAutoresizingMaskIntoConstraints(false)
    view1.backgroundColor = UIColor.redColor()

    //Make the scroll view
    let view2 = UIScrollView()
    view2.setTranslatesAutoresizingMaskIntoConstraints(false)
    view2.backgroundColor = UIColor(red: 0.75, green: 0.75, blue: 0.1, alpha: 1.0)

    view.addSubview(view1)
    view1.addSubview(view2)

    var dictionary = [String: UIView]()
    dictionary.updateValue(view1, forKey: "view1")

    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])

    dictionary = [String: UIView]()
    dictionary.updateValue(view2, forKey: "view2")

    view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
    view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])

    //Create the buttons
    for i in 0...(sceneCount-1) {
        var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton

        button.setTranslatesAutoresizingMaskIntoConstraints(false)
        button.addTarget(self, action: Selector("scene\(i)Pressed"), forControlEvents: UIControlEvents.TouchUpInside)
        button.setBackgroundImage(UIImage(named: "Scene\(i+1)"), forState: UIControlState.Normal)
        button.sizeThatFits(CGSizeMake(40, 40))

        buttons.append(button)
        view2.addSubview(button)
    }

    //set vertical spacing for all buttons
    for i in 0...(sceneCount-1) {
        var button1 = buttons[i]
        var dictionary2 = [String: UIButton]()
        dictionary2.updateValue(button1, forKey: "button1")

        view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[button1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary2) as [AnyObject])
    }

    //set horizontal distance to container for first button
    if sceneCount > 0 {
        var buttonFirst: UIButton = buttons[0]
        var dictionary3 = [String: UIButton]()
        dictionary3.updateValue(buttonFirst, forKey: "buttonFirst")
        view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[buttonFirst]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary3) as [AnyObject])
    }

    //set horizontal spacing between the buttons
    for i in 1...(sceneCount-1) {
        var button1 = buttons[i - 1]
        var button2 = buttons[i]

        var dictionary1 = [String: UIButton]()
        dictionary1.updateValue(button1, forKey: "scene1")
        dictionary1.updateValue(button2, forKey: "scene2")

        view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[scene1]-[scene2]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary1) as [AnyObject])
    }

    //set horizontal distance to container for last button
    if sceneCount > 0 {
        var buttonLast: UIButton = buttons[sceneCount-1]
        var dictionary4 = [String: UIButton]()
        dictionary4.updateValue(buttonLast, forKey: "buttonLast")
        view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[buttonLast]-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary4) as [AnyObject])
    }

}

override func viewDidLoad() {
    super.viewDidLoad()
    makeLayout()
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM