MKMapView 与零高度约束斗争 - 地图视图的 edgeInsets?

MKMapView struggles with zero height constraint - edgeInsets of map view?

我有一个 MKMapView 大约 300 高,它在其他两个视图之间折叠,只需像折叠视图时通常做的那样上下动画高度。

@IBOutlet var heightMap: NSLayoutConstraint!
@IBOutlet var theMap: MKMapView!

视图启动时高度为零..

override func viewDidLoad() {
    super.viewDidLoad()
    ..
    heightMap.constant = 0
}

有一个令人气愤的警告...

[LayoutConstraints] 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:0x6080000904f0 MKMapView:0x7fe6b3000600.height == 0   (active)>",
    "<NSLayoutConstraint:0x608000093a60 UILayoutGuide:0x60800018fd80'Edge Insets'.top == MKMapView:0x7fe6b3000600.top + 8   (active)>",
    "<NSLayoutConstraint:0x608000093b50 UILayoutGuide:0x60800018fd80'Edge Insets'.bottom == MKMapView:0x7fe6b3000600.bottom   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x608000093b50 UILayoutGuide:0x60800018fd80'Edge Insets'.bottom == MKMapView:0x7fe6b3000600.bottom   (active)>

请注意,它似乎正在与 "edgeInsets" 或可能 "Edge Insets"(带有 space!)顶部和底部作斗争,

'Edge Insets'.top == MKMapView:0x7fe6b3000600.top + 8
'Edge Insets'.bottom == MKMapView:0x7fe6b3000600.bottom

地图视图具有只读 属性 .alignmentRectInsets

(实际上,当我打印出来时,无论它是什么,它都是零..

let ari = theMap.alignmentRectInsets
print("wth \(ari)")
> wth UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)

)

我什至在 MKMapView 上找不到任何关于 "edge insets" 的信息,这是怎么回事?

我仔细检查了未安装的约束和常见问题。

有趣的是,如果初始高度为零,我只会收到此错误,因此这似乎是地图视图初始设置的问题。他们的解决方案似乎是

  1. 在情节提要中给 mapView 一个高度(我做了 100 个)
  2. 制作 通过在界面生成器中选中隐藏框来隐藏 mapView

何时显示 mapView:

  1. 取消隐藏
  2. 最小化它(我将常量设置为 .ulpOfOne 而不是零,因为从技术上讲帧不应该退化。)
  3. 动画到最终位置

    class ViewController: UIViewController{
        @IBOutlet weak var m: MKMapView!
        @IBOutlet weak var h: NSLayoutConstraint!
        @IBAction func t(_ sender: Any) {
            m.isHidden = false
            h.constant = .ulpOfOne
            view.layoutIfNeeded()
            h.constant = 100
            UIView.animate(withDuration: 3) {
                self.view.layoutIfNeeded()
            }
        }
    }
    

仅供参考,我实际上会为此使用 UIStackView,而只是为 isHidden 设置动画,然后您甚至不必处理代码中的约束。

我一直在为同样的问题而苦苦挣扎,每次我想隐藏 MKMapView(手动使用高度限制或在 UIStackView 中)时都会收到此警告。我注意到我可以通过在激活零高度约束之前将地图视图的边界高度设置为 0 来防止警告。所以写了一点class来封装bug:

import MapKit

class HideableMapView: MKMapView {

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        if self.containsZeroHeightConstraint() {
            // Set the bounds manually before the constraint gets processed to prevent an auto layout warning
            self.bounds.size.height = 0
        }

        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }

    private func containsZeroHeightConstraint() -> Bool {
        return (self.constraints.filter { [=10=].firstAttribute == .height && [=10=].constant == 0 }).isEmpty == false
    }
}

这 class 适用于我的项目,其中 MKMapView 嵌入在 UIStackView 中。根据您的设置,您可能必须覆盖另一种方法。为UIViewAlertForUnsatisfiableConstraints设置符号断点,查看调用栈。

我也提交了一个雷达,你可以在这里找到:https://openradar.appspot.com/radar?id=6109127172423680