I can’t set the switch next to my label. Not sure why. At one point, I had set the switch’s leading and trailing constraints up the same way as I did my label. While I could set .top and .bottom attributes up in poiSwitchConstraint so that they appeared on on top of one another, I can’t identify the right attributes to set them up next to each other. If I go .left and .right, the switch does not appear at all.
// Bronze Challenge: Add a UILabel and UISwitch to the MapViewController interface
let poiLabel = UILabel()
poiLabel.text = "Points of Interest"
let poiSwitch = UISwitch()
poiSwitch.isOn = false
poiLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(poiLabel)
poiSwitch.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(poiSwitch)
let poiLabelLeadingConstraint = poiLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor)
let poiLabelTrailingConstraint = poiLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
poiLabelLeadingConstraint.isActive = true
poiLabelTrailingConstraint.isActive = true
// explicit constraint for Label
let poiLabelConstraint = NSLayoutConstraint(item: poiLabel, attribute: .top, relatedBy: .equal, toItem: segmentedControl, attribute: .bottom, multiplier: 1.0, constant: 8.0)
poiLabelConstraint.isActive = true
// explicit constraint for switch
let poiSwitchConstraint = NSLayoutConstraint(item: poiSwitch, attribute: .left, relatedBy: .equal, toItem: poiLabel, attribute: .right, multiplier: 1.0, constant: 8.0)
poiSwitchConstraint.isActive = true
The trailing edge of your label should not be anchored to the trailing margin. When you put that together with the leading edge being constrained to the leading margin that’s going to stretch the label across the entire screen, and the switch winds up getting pushed off screen. I think that’s what’s messing things up for you, try removing the trailing anchor constraint.
You’re also going to want a constraint connecting the vertical center of the switch to the vertical center of the label. Right now there’s no constraint controlling the vertical position of the switch, so it’s being put wherever the switch’s init function sets it by default.
I added this at the end, but placed the switch underneath the label, not next to it:
let poiSwitchConstraint = NSLayoutConstraint(item: poiSwitch, attribute: .centerY, relatedBy: .equal, toItem: segmentedControl, attribute: .centerY, multiplier: 1.0, constant: 8.0)
poiSwitchConstraint.isActive = true
When you mention a constraint connecting the vertical centers of the two objects, did you mean that I need to add a
.centerYAnchor.constraint
for my switch instead?
If you’re placing the switch beneath the label, then you’d want to add a constraint connecting the top anchor of the switch to the bottom anchor of the label. I don’t see how the constraint you added puts the switch underneath the label.
Ha! My fault – that’s because I originally set the multiplier to 5.0, not 1.0. Set to the latter, the switch virtually imposes on top of the label.
No, I’d really like to match the screens in the book. Back to my previous question to that effect: do I need add .centerYAnchor.constraint for my switch?
Yes. Since you have a constraint positioning the label below the segmented control, you should add one equating the centerYanchor of the switch to the centerYanchor of the label.
Thanks - finally got it to work
let poiSwitchCenterConstraint = poiSwitch.centerYAnchor.constraint(equalTo: poiLabel.centerYAnchor)
poiSwitchCenterConstraint.isActive = true
let poiSwitchConstraint = NSLayoutConstraint(item: poiSwitch, attribute: .centerX, relatedBy: .equal, toItem: segmentedControl, attribute: .centerX, multiplier: 1.0, constant: 8.0)
poiSwitchConstraint.isActive = true
@Caps5150 Thanks for sharing your solution, it was very helpful to see your approach. I found an easier way to add constraints that didn’t require manually setting isActive = true
for each constraint.
Here is my solution:
import UIKit
import MapKit
class MapViewController: UIViewController {
var mapView: MKMapView!
let poiLabel = UILabel()
let poiSwitch = UISwitch()
let segmentedControl = UISegmentedControl(items: ["Standard", "Hybrid", "Satellite"])
override func loadView() {
mapView = MKMapView()
view = mapView
segmentedControl.backgroundColor = UIColor.systemBackground
segmentedControl.selectedSegmentIndex = 0
segmentedControl.addTarget(self, action: #selector(mapTypeChanged(_:)), for: .valueChanged)
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(segmentedControl)
poiLabel.text = "Points of Interest"
poiLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(poiLabel)
poiSwitch.translatesAutoresizingMaskIntoConstraints = false
poiSwitch.isOn = false
poiSwitch.addTarget(self, action: #selector(poiSelect(_:)), for: .valueChanged)
view.addSubview(poiSwitch)
NSLayoutConstraint.activate([
segmentedControl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 1),
segmentedControl.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
segmentedControl.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
poiLabel.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8),
poiLabel.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
poiSwitch.topAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8),
poiSwitch.leadingAnchor.constraint(equalTo: poiLabel.trailingAnchor, constant: 4),
poiSwitch.centerYAnchor.constraint(equalTo: poiLabel.centerYAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func poiSelect(_ switchVal: UISwitch) {
if (switchVal.isOn) {
mapView.pointOfInterestFilter = MKPointOfInterestFilter.includingAll
} else {
mapView.pointOfInterestFilter = MKPointOfInterestFilter.excludingAll
}
}
@objc func mapTypeChanged(_ segControl: UISegmentedControl) {
switch segControl.selectedSegmentIndex {
case 0:
mapView.mapType = .standard
poiLabel.textColor = UIColor.black
case 1:
mapView.mapType = .hybrid
poiLabel.textColor = UIColor.white
case 2:
mapView.mapType = .satellite
poiLabel.textColor = UIColor.white
default:
break;
}
}
}
1 Like