Skip to content

Commit

Permalink
Update LearnAboutAutoLayout.playground
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Hyche committed Aug 9, 2017
1 parent 68c75d0 commit d7f8d10
Show file tree
Hide file tree
Showing 21 changed files with 511 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))
let container = liveView.containerView

func createButton(withTitle title: String) -> UIButton {
let button = UIButton(frame: .zero)
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.backgroundColor = UIColor.darkGray
return button
}

let shortButton = createButton(withTitle: "Short")
let longButton = createButton(withTitle: "Much Longer Button Title")

shortButton.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(shortButton)

longButton.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(longButton)

// |-[short]-(8)-[long]-|
shortButton.leadingAnchor.constraint(equalTo: container.layoutMarginsGuide.leadingAnchor).isActive = true
let betwixt = longButton.leadingAnchor.constraint(equalTo: shortButton.trailingAnchor, constant: 8.0)
betwixt.identifier = "Space Between Short and Long"
betwixt.isActive = true
longButton.trailingAnchor.constraint(equalTo: container.layoutMarginsGuide.trailingAnchor).isActive = true

container.layoutMarginsGuide.bottomAnchor.constraint(equalTo: shortButton.bottomAnchor, constant: 20.0).isActive = true
container.layoutMarginsGuide.bottomAnchor.constraint(equalTo: longButton.bottomAnchor, constant: 20.0).isActive = true

shortButton.widthAnchor.constraint(equalTo: longButton.widthAnchor).isActive = true

for constraint in container.constraints {
print("\(constraint)")
}


PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))
let container = liveView.containerView

let labelFontSizeSmall: CGFloat = 16.0
let labelFontSizeLarge: CGFloat = 32.0

func label(withText text: String) -> UILabel {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.black
label.font = UIFont.boldSystemFont(ofSize: labelFontSizeSmall)
// label.font = UIFont.boldSystemFont(ofSize: labelFontSizeLarge)
label.text = text
return label
}

func textField(withPlaceholder placeholder: String) -> UITextField {
let textField = UITextField(frame: .zero)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.borderStyle = .roundedRect
textField.placeholder = placeholder

return textField
}

let firstLabel = label(withText: "First Name")
let firstTextField = textField(withPlaceholder: "Enter first name")
let middleLabel = label(withText: "Middle Name")
let middleTextField = textField(withPlaceholder: "Enter middle name")
let lastLabel = label(withText: "Last Name")
let lastTextField = textField(withPlaceholder: "Enter last name")

container.addSubview(firstLabel)
container.addSubview(firstTextField)
container.addSubview(middleLabel)
container.addSubview(middleTextField)
container.addSubview(lastLabel)
container.addSubview(lastTextField)

// |-[firstLabel]-(8)-[firstTextField]-|
firstLabel.leadingAnchor.constraint(equalTo: container.layoutMarginsGuide.leadingAnchor).isActive = true
firstTextField.leadingAnchor.constraint(equalTo: firstLabel.trailingAnchor, constant: 8.0).isActive = true
firstTextField.trailingAnchor.constraint(equalTo: container.layoutMarginsGuide.trailingAnchor).isActive = true

// Middle label and text field
middleLabel.leadingAnchor.constraint(equalTo: firstLabel.leadingAnchor).isActive = true
middleTextField.leadingAnchor.constraint(equalTo: middleLabel.trailingAnchor, constant: 8.0).isActive = true
middleTextField.trailingAnchor.constraint(equalTo: firstTextField.trailingAnchor).isActive = true


lastLabel.leadingAnchor.constraint(equalTo: firstLabel.leadingAnchor).isActive = true
lastTextField.leadingAnchor.constraint(equalTo: lastLabel.trailingAnchor, constant: 8.0).isActive = true
lastTextField.trailingAnchor.constraint(equalTo: firstTextField.trailingAnchor).isActive = true

// Align baselines
firstLabel.firstBaselineAnchor.constraint(equalTo: firstTextField.firstBaselineAnchor).isActive = true
middleLabel.firstBaselineAnchor.constraint(equalTo: middleTextField.firstBaselineAnchor).isActive = true
lastLabel.firstBaselineAnchor.constraint(equalTo: lastTextField.firstBaselineAnchor).isActive = true

// Make all text field widths the same
firstTextField.widthAnchor.constraint(equalTo: middleTextField.widthAnchor).isActive = true
firstTextField.widthAnchor.constraint(equalTo: lastTextField.widthAnchor).isActive = true

// Handle where either the label or text field could be taller
func setupRequiredMinWithOptionalEquality(anchorY1: NSLayoutYAxisAnchor, anchorY2: NSLayoutYAxisAnchor, constant: CGFloat, priority: UILayoutPriority) {
anchorY1.constraint(greaterThanOrEqualTo: anchorY2, constant: constant).isActive = true
let equality = anchorY1.constraint(equalTo: anchorY2, constant: constant)
equality.priority = priority
equality.isActive = true
}

setupRequiredMinWithOptionalEquality(anchorY1: firstLabel.topAnchor, anchorY2: container.layoutMarginsGuide.topAnchor, constant: 20.0, priority: 249)
setupRequiredMinWithOptionalEquality(anchorY1: firstTextField.topAnchor, anchorY2: container.layoutMarginsGuide.topAnchor, constant: 20.0, priority: 249)

setupRequiredMinWithOptionalEquality(anchorY1: middleLabel.topAnchor, anchorY2: firstLabel.bottomAnchor, constant: 8.0, priority: 249)
setupRequiredMinWithOptionalEquality(anchorY1: middleTextField.topAnchor, anchorY2: firstTextField.bottomAnchor, constant: 8.0, priority: 249)

setupRequiredMinWithOptionalEquality(anchorY1: lastLabel.topAnchor, anchorY2: middleLabel.bottomAnchor, constant: 8.0, priority: 249)
setupRequiredMinWithOptionalEquality(anchorY1: lastTextField.topAnchor, anchorY2: middleTextField.bottomAnchor, constant: 8.0, priority: 249)


// We set the content hugging priority so that
// the labels have a higher content hugging priority
// than do the text fields. What happens if we reverse these?
let labelPriority = UILayoutPriorityDefaultLow + 1
let textFieldPriority = UILayoutPriorityDefaultLow
firstLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
middleLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
lastLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
firstTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)
middleTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)
lastTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)


PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))

let yellow = UIView(frame: .zero)
yellow.translatesAutoresizingMaskIntoConstraints = false
yellow.backgroundColor = UIColor.yellow

liveView.containerView.addSubview(yellow)

let green = UIView(frame: .zero)
green.translatesAutoresizingMaskIntoConstraints = false
green.backgroundColor = UIColor.green

liveView.containerView.addSubview(green)

yellow.leadingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.leadingAnchor).isActive = true
green.leadingAnchor.constraint(equalTo: yellow.trailingAnchor, constant: 8.0).isActive = true
green.trailingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.trailingAnchor).isActive = true
// Attach the top of the yellow and green
yellow.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
green.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
// Attach the bottom of yellow and green
yellow.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
green.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
// Now set the width of yellow and green to be the same
yellow.widthAnchor.constraint(equalTo: green.widthAnchor).isActive = true

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))
let container = liveView.containerView

let labelFontSizeSmall: CGFloat = 16.0
let labelFontSizeLarge: CGFloat = 32.0

func label(withText text: String) -> UILabel {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.black
label.font = UIFont.boldSystemFont(ofSize: labelFontSizeSmall)
// label.font = UIFont.boldSystemFont(ofSize: labelFontSizeLarge)
label.text = text
return label
}

func textField(withPlaceholder placeholder: String) -> UITextField {
let textField = UITextField(frame: .zero)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.borderStyle = .roundedRect
textField.placeholder = placeholder

return textField
}

let firstLabel = label(withText: "First Name")
let firstTextField = textField(withPlaceholder: "Enter first name")
let middleLabel = label(withText: "Middle Name")
let middleTextField = textField(withPlaceholder: "Enter middle name")
let lastLabel = label(withText: "Last Name")
let lastTextField = textField(withPlaceholder: "Enter last name")

container.addSubview(firstLabel)
container.addSubview(firstTextField)
container.addSubview(middleLabel)
container.addSubview(middleTextField)
container.addSubview(lastLabel)
container.addSubview(lastTextField)

// |-[firstLabel]-(8)-[firstTextField]-|
firstLabel.leadingAnchor.constraint(equalTo: container.layoutMarginsGuide.leadingAnchor).isActive = true
firstTextField.leadingAnchor.constraint(equalTo: firstLabel.trailingAnchor, constant: 8.0).isActive = true
firstTextField.trailingAnchor.constraint(equalTo: container.layoutMarginsGuide.trailingAnchor).isActive = true

// Middle label and text field
middleLabel.leadingAnchor.constraint(equalTo: firstLabel.leadingAnchor).isActive = true
middleTextField.leadingAnchor.constraint(equalTo: middleLabel.trailingAnchor, constant: 8.0).isActive = true
middleTextField.trailingAnchor.constraint(equalTo: firstTextField.trailingAnchor).isActive = true


lastLabel.leadingAnchor.constraint(equalTo: firstLabel.leadingAnchor).isActive = true
lastTextField.leadingAnchor.constraint(equalTo: lastLabel.trailingAnchor, constant: 8.0).isActive = true
lastTextField.trailingAnchor.constraint(equalTo: firstTextField.trailingAnchor).isActive = true

// Align baselines
firstLabel.firstBaselineAnchor.constraint(equalTo: firstTextField.firstBaselineAnchor).isActive = true
middleLabel.firstBaselineAnchor.constraint(equalTo: middleTextField.firstBaselineAnchor).isActive = true
lastLabel.firstBaselineAnchor.constraint(equalTo: lastTextField.firstBaselineAnchor).isActive = true

// Make all text field widths the same
firstTextField.widthAnchor.constraint(equalTo: middleTextField.widthAnchor).isActive = true
firstTextField.widthAnchor.constraint(equalTo: lastTextField.widthAnchor).isActive = true

// Pin first label to top margin
firstLabel.topAnchor.constraint(equalTo: container.layoutMarginsGuide.topAnchor).isActive = true


// These constraints put space between the rows. But we
// are assuming that the text fields are taller than the
// labels. What happens if they are not?
middleTextField.topAnchor.constraint(equalTo: firstTextField.bottomAnchor, constant: 20.0).isActive = true
lastTextField.topAnchor.constraint(equalTo: middleTextField.bottomAnchor, constant: 20.0).isActive = true

// We set the content hugging priority so that
// the labels have a higher content hugging priority
// than do the text fields. What happens if we reverse these?
let labelPriority = UILayoutPriorityDefaultLow + 1
let textFieldPriority = UILayoutPriorityDefaultLow
firstLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
middleLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
lastLabel.setContentHuggingPriority(labelPriority, for: .horizontal)
firstTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)
middleTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)
lastTextField.setContentHuggingPriority(textFieldPriority, for: .horizontal)


PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ liveView.containerView.addConstraint(label0leading)
liveView.containerView.addConstraint(label1trailing)
liveView.containerView.addConstraint(label0label1gap)

for constraint in liveView.containerView.constraints {
print("\(constraint)")
}

for constraint in label0.constraints {
print("\(constraint)")
}

for constraint in label1.constraints {
print("\(constraint)")
}

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))

let purple = UIView(frame: .zero)
purple.translatesAutoresizingMaskIntoConstraints = false
purple.backgroundColor = UIColor.purple

liveView.containerView.addSubview(purple)

let orange = UIView(frame: .zero)
orange.translatesAutoresizingMaskIntoConstraints = false
orange.backgroundColor = UIColor.orange

liveView.containerView.addSubview(orange)

purple.leadingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.leadingAnchor).isActive = true
orange.leadingAnchor.constraint(equalTo: purple.trailingAnchor, constant: 8.0).isActive = true
orange.trailingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.trailingAnchor).isActive = true
// Attach the top of the yellow and green
purple.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
orange.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
// Attach the bottom of yellow and green
purple.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
orange.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
// Now set orange's width to be 2x of purple's width
orange.widthAnchor.constraint(equalTo: purple.widthAnchor, multiplier: 2.0).isActive = true

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Timeline
version = "3.0">
<TimelineItems>
</TimelineItems>
</Timeline>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import UIKit
import PlaygroundSupport

// This is our sample container view which allows us
// to adjust the width and height of the container
let liveView = EHAdjustableContainerView(frame: CGRect(x: 0.0, y: 0.0, width: 512.0, height: 512.0))

let blue = UIView(frame: .zero)
blue.translatesAutoresizingMaskIntoConstraints = false
blue.backgroundColor = UIColor.blue

liveView.containerView.addSubview(blue)

let red = UIView(frame: .zero)
red.translatesAutoresizingMaskIntoConstraints = false
red.backgroundColor = UIColor.red

liveView.containerView.addSubview(red)

blue.leadingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.leadingAnchor).isActive = true
red.leadingAnchor.constraint(equalTo: blue.trailingAnchor, constant: 8.0).isActive = true
red.trailingAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.trailingAnchor).isActive = true
// Attach the top of the yellow and green
blue.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
red.topAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.topAnchor).isActive = true
// Attach the bottom of yellow and green
blue.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
red.bottomAnchor.constraint(equalTo: liveView.containerView.layoutMarginsGuide.bottomAnchor).isActive = true
// Now set red's width to be 2x of blue's width (@750)
let widthConstraint = red.widthAnchor.constraint(equalTo: blue.widthAnchor, multiplier: 2.0)
widthConstraint.priority = UILayoutPriorityDefaultHigh
widthConstraint.isActive = true

blue.widthAnchor.constraint(greaterThanOrEqualToConstant: 50.0).isActive = true

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
Loading

0 comments on commit d7f8d10

Please sign in to comment.