以编程方式向 Swift 中的视图添加约束时出错

sin*_*eil 5 ios autolayout swift

我在日志中收到错误,告诉我在以编程方式向 Swift 中的视图添加约束时,存在无法同时满足的冲突约束,但正如您所见,在运行模拟器时,UI 看起来是我想要的样子在屏幕截图中。左侧按钮的前缘与分段控件的前缘对齐,右侧按钮的后缘与分段控件的后缘对齐。

我相信正是这些约束导致了问题,因为将这 2 个注释掉是阻止错误被抛出的原因,但是 UI 看起来并不像我想要的那样。

有人可以帮我理解我做错了什么吗?

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.
Run Code Online (Sandbox Code Playgroud)
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")
}
Run Code Online (Sandbox Code Playgroud)

}


布局的屏幕截图,即使日志中有约束错误

vac*_*ama 4

你的问题是因为你没有给你MKMapView一个适当的frame。当你像这样创建它时:

mapView = MKMapView()
Run Code Online (Sandbox Code Playgroud)

您正在设置框架的0宽度和0高度。然后,自动布局将该框架转换为视图宽度和高度的约束。

列出的冲突约束之一是:

<NSLayoutConstraint:0x7fd836318800 'UIView-Encapsulated-Layout-Width' H:[MKMapView:0x7fd83351d900(0)]>
Run Code Online (Sandbox Code Playgroud)

in表示有一个约束使 to 的宽度为0,这当然不是你想要的。[MKMapView:0x7fd83351d900(0)]MKMapView0

您可以通过在创建地图视图时为其提供适当的框架来解决此问题:

代替:

mapView = MKMapView()
Run Code Online (Sandbox Code Playgroud)

和:

mapView = MKMapView(frame: UIScreen.mainScreen().bounds)
Run Code Online (Sandbox Code Playgroud)

我下面的答案通过让 iOS 设置视图解决了这个问题,它做得正确。


上一个答案

我最初无法重现您的问题,但是当我将 viewController 放入 a 中时UITabBarController,我也看到了自动布局错误消息。

为了使其正常工作,我UIViewControllerStoryboard中使用了一个标准,并将您的loadView代码移至viewDidLoad. 我添加了MKMapView作为 的子视图self.view以及适当的约束,以使其大小与 相同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
    
}
Run Code Online (Sandbox Code Playgroud)

替代解决方案:

  1. 将您的loadView代码移至viewDidLoad并删除这些行:

    mapView = MKMapView()
    view = mapView
    
    Run Code Online (Sandbox Code Playgroud)
  2. Storyboard中,将的类更改view为。ViewControllerMKMapView

  3. 制作mapView一个@IBOutlet

     @IBOutlet var mapView: MKMapView!
    
    Run Code Online (Sandbox Code Playgroud)
  4. 连接情节提要中的插座。

  5. 设置MKMapView代表。- 从StoryboardControl拖动到顶部的ViewController图标,然后从弹出窗口中选择委托。您还可以通过调用以下方式连接委托:mapViewviewController

    mapView.delegate = self
    
    Run Code Online (Sandbox Code Playgroud)

    viewDidLoad