I'm getting errors in the log that tell me there are conflicting constraints that can't be simultaneously satisfied when programatically adding constraints to views in Swift, yet the UI is looking the way I intended it to when running the simulator as you can see in the screenshot. The leading edge of the left button is aligned with the leading edge of the segmented control, the trailing edge of the right button is aligned with the trailing edge of the segmented control.
I believe it's these constraints causing problems, as commenting those 2 out is what's stopping the errors from being thrown, but then the UI doesn't look as I intended.
Could someone please help me understand what I've done wrong?
Conversion View Controller loaded
2016-07-29 22:51:34.555 WorldTrotter[800:41503] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x7fd836313550 UIButton:0x7fd836312e60'Current Location'.left == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.left>",
"<NSLayoutConstraint:0x7fd836313660 UIButton:0x7fd836312e60'Current Location'.trailing == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.centerX - 8>",
"<NSLayoutConstraint:0x7fd836318800 'UIView-Encapsulated-Layout-Width' H:[MKMapView:0x7fd83351d900(0)]>",
"<NSLayoutConstraint:0x7fd836312e00 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'](LTR) (Names: '|':MKMapView:0x7fd83351d900 )>",
"<NSLayoutConstraint:0x7fd833794d30 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide']-(0)-|(LTR) (Names: '|':MKMapView:0x7fd83351d900 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fd836313660 UIButton:0x7fd836312e60'Current Location'.trailing == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.centerX - 8>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-07-29 22:51:34.556 WorldTrotter[800:41503] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x7fd836313ee0 UIButton:0x7fd8363136b0'Next Pin'.leading == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.centerX + 8>",
"<NSLayoutConstraint:0x7fd836313fb0 UIButton:0x7fd8363136b0'Next Pin'.trailing == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.trailing>",
"<NSLayoutConstraint:0x7fd836318800 'UIView-Encapsulated-Layout-Width' H:[MKMapView:0x7fd83351d900(0)]>",
"<NSLayoutConstraint:0x7fd836312e00 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'](LTR) (Names: '|':MKMapView:0x7fd83351d900 )>",
"<NSLayoutConstraint:0x7fd833794d30 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide']-(0)-|(LTR) (Names: '|':MKMapView:0x7fd83351d900 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fd836313fb0 UIButton:0x7fd8363136b0'Next Pin'.trailing == UILayoutGuide:0x7fd83630fc20'UIViewLayoutMarginsGuide'.trailing>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
var mapView: MKMapView!
let locationManager = CLLocationManager()
var coordinates: [CLLocationCoordinate2D] = []
var counter: Int = 0
override func loadView() {
mapView = MKMapView()
mapView.delegate = self
view = mapView
//Adding pins to map
let firstLocation = CLLocationCoordinate2DMake(5.000000, -5.000000)
let secondLocation = CLLocationCoordinate2DMake(-5.000000, 5.000000)
coordinates.append(firstLocation)
coordinates.append(secondLocation)
let segmentedControl = UISegmentedControl(items: ["Standard", "Hybrid", "Satellite"])
segmentedControl.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.5)
segmentedControl.selectedSegmentIndex = 0
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.addTarget(self, action: #selector(MapViewController.mapTypeChanged(_:)), forControlEvents: .ValueChanged)
view.addSubview(segmentedControl)
let margins = view.layoutMarginsGuide
let topConstraint = segmentedControl.topAnchor.constraintEqualToAnchor(topLayoutGuide.bottomAnchor, constant: 8)
let leadingConstraint = segmentedControl.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor)
let trailingConstraint = segmentedControl.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
topConstraint.active = true
leadingConstraint.active = true
trailingConstraint.active = true
let userButton = UIButton()
view.addSubview(userButton)
userButton.translatesAutoresizingMaskIntoConstraints = false
userButton.addTarget(self, action: #selector(MapViewController.userButtonSelected(_:)), forControlEvents: UIControlEvents.TouchUpInside)
userButton.setTitle("Current Location", forState: .Normal)
userButton.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.7)
let bTopConstraint = userButton.topAnchor.constraintEqualToAnchor(segmentedControl.bottomAnchor, constant: 8)
//Problematic constraint I think
let bLConstraint = userButton.leftAnchor.constraintEqualToAnchor(margins.leftAnchor)
let bTConstraint = userButton.trailingAnchor.constraintEqualToAnchor(margins.centerXAnchor, constant: -8)
bTopConstraint.active = true
bLConstraint.active = true
bTConstraint.active = true
let pinsButton = UIButton()
view.addSubview(pinsButton)
pinsButton.translatesAutoresizingMaskIntoConstraints = false
pinsButton.addTarget(self, action: #selector(MapViewController.pinsButtonSelected(_:)), forControlEvents: UIControlEvents.TouchUpInside)
pinsButton.setTitle("Next Pin", forState: .Normal)
pinsButton.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.7)
let pTopConstraint = pinsButton.topAnchor.constraintEqualToAnchor(segmentedControl.bottomAnchor, constant: 8)
//Problematic constraint I think
let pLConstraint = pinsButton.leadingAnchor.constraintEqualToAnchor(margins.centerXAnchor, constant: 8)
let pTConstraint = pinsButton.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
pTopConstraint.active = true
pLConstraint.active = true
pTConstraint.active = true
}
func mapTypeChanged(segControl: UISegmentedControl) {
switch segControl.selectedSegmentIndex {
case 0:
mapView.mapType = .Standard
case 1:
mapView.mapType = .Hybrid
case 2:
mapView.mapType = .Satellite
default:
break
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
func userButtonSelected(button: UIButton) {
if mapView.showsUserLocation == false {
mapView.showsUserLocation = true
} else {
mapView.showsUserLocation = false
}
}
func pinsButtonSelected(button: UIButton) {
if counter >= coordinates.count {
counter = 0
}
let dropPin = MKPointAnnotation()
dropPin.coordinate = coordinates[counter]
counter += 1
mapView.addAnnotation(dropPin)
mapView.setCenterCoordinate(dropPin.coordinate, animated: false)
}
func mapViewWillStartLocatingUser(mapView: MKMapView) {
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
mapView.setUserTrackingMode(MKUserTrackingMode.Follow, animated: true)
print("Tracking user")
}
}
You cannot add a check constraint to a materialized view. You can “roll it by hand” by creating a table and using TRUNCATE and INSERT ... SELECT to refresh the data.
translatesAutoresizingMaskIntoConstraints. A Boolean value that determines whether the view's autoresizing mask is translated into Auto Layout constraints.
To create a constraint between two views, Control-click one of the views and drag to the other. When you release the mouse, Interface Builder displays a HUD menu with a list of possible constraints.
Your problem is coming from the fact that you haven't given your MKMapView
a proper frame
. When you create it like this:
mapView = MKMapView()
You are setting the frame to 0
width and 0
height. Auto Layout is then translating that frame into constraints for the width and height of the view.
One of the conflicting constraints listed is:
<NSLayoutConstraint:0x7fd836318800 'UIView-Encapsulated-Layout-Width' H:[MKMapView:0x7fd83351d900(0)]>
The 0
in [MKMapView:0x7fd83351d900(0)]
indicates that there is a constraint to make the width of MKMapView
to be 0
, which of course is not what you want.
You can fix this by giving your map view a proper frame when you create it:
Replace:
mapView = MKMapView()
with:
mapView = MKMapView(frame: UIScreen.mainScreen().bounds)
My answers below worked around this problem by letting iOS set up the view, which it does correctly.
I was not able to reproduce your problem initially, but when I put your viewController in a UITabBarController
, I too saw the Auto Layout error messages.
To make it work, I used a standard UIViewController
in the Storyboard and moved your loadView
code into viewDidLoad
. I added the MKMapView
as a subview of self.view
along with appropriate constraints to make it the same size as self.view
:
override func viewDidLoad() {
super.viewDidLoad()
mapView = MKMapView()
mapView.delegate = self
mapView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(mapView)
NSLayoutConstraint.activateConstraints([
mapView.topAnchor.constraintEqualToAnchor(view.topAnchor),
mapView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
mapView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor),
mapView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
])
//Adding pins to map
let firstLocation = CLLocationCoordinate2DMake(5.000000, -5.000000)
let secondLocation = CLLocationCoordinate2DMake(-5.000000, 5.000000)
coordinates.append(firstLocation)
coordinates.append(secondLocation)
let segmentedControl = UISegmentedControl(items: ["Standard", "Hybrid", "Satellite"])
segmentedControl.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.5)
segmentedControl.selectedSegmentIndex = 0
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControl.addTarget(self, action: #selector(MapViewController.mapTypeChanged(_:)), forControlEvents: .ValueChanged)
view.addSubview(segmentedControl)
let margins = view.layoutMarginsGuide
let topConstraint = segmentedControl.topAnchor.constraintEqualToAnchor(topLayoutGuide.bottomAnchor, constant: 8)
let leadingConstraint = segmentedControl.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor)
let trailingConstraint = segmentedControl.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
topConstraint.active = true
leadingConstraint.active = true
trailingConstraint.active = true
let userButton = UIButton()
view.addSubview(userButton)
userButton.translatesAutoresizingMaskIntoConstraints = false
userButton.addTarget(self, action: #selector(MapViewController.userButtonSelected(_:)), forControlEvents: UIControlEvents.TouchUpInside)
userButton.setTitle("Current Location", forState: .Normal)
userButton.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.7)
let bTopConstraint = userButton.topAnchor.constraintEqualToAnchor(segmentedControl.bottomAnchor, constant: 8)
//Problematic constraint I think
let bLConstraint = userButton.leftAnchor.constraintEqualToAnchor(margins.leftAnchor)
let bTConstraint = userButton.trailingAnchor.constraintEqualToAnchor(margins.centerXAnchor, constant: -8)
bTopConstraint.active = true
bLConstraint.active = true
bTConstraint.active = true
let pinsButton = UIButton()
view.addSubview(pinsButton)
pinsButton.translatesAutoresizingMaskIntoConstraints = false
pinsButton.addTarget(self, action: #selector(MapViewController.pinsButtonSelected(_:)), forControlEvents: UIControlEvents.TouchUpInside)
pinsButton.setTitle("Next Pin", forState: .Normal)
pinsButton.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.7)
let pTopConstraint = pinsButton.topAnchor.constraintEqualToAnchor(segmentedControl.bottomAnchor, constant: 8)
//Problematic constraint I think
let pLConstraint = pinsButton.leadingAnchor.constraintEqualToAnchor(margins.centerXAnchor, constant: 8)
let pTConstraint = pinsButton.trailingAnchor.constraintEqualToAnchor(margins.trailingAnchor)
pTopConstraint.active = true
pLConstraint.active = true
pTConstraint.active = true
}
Move your loadView
code to viewDidLoad
and get rid of these lines:
mapView = MKMapView()
view = mapView
In the Storyboard, change the class of the view
in the ViewController
to MKMapView
.
Make the mapView
an @IBOutlet
:
@IBOutlet var mapView: MKMapView!
Wire up the outlet in the Storyboard.
Set the MKMapView
delegate. Control-drag from mapView
in Storyboard to the ViewController icon at the top of the viewController
and select delegate from the pop-up. You could also hook up the delegate by calling:
mapView.delegate = self
in viewDidLoad
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With