iOS - 旋转设备时 NSLayoutConstraint 问题

iOS - Issue with NSLayoutConstraint when rotating device

我有一个 iOS 视图,其中包含一个 collection 视图和一个 header 视图。视图显示正常,但是当我旋转设备 (iPad) 时,header 元素重复并且无法正确匹配。输出 window 显示以下

(
"<NSLayoutConstraint:0x600000051860 H:|-(0)-[UIImageView:0x7fe602031e40]   (active, names: '|':MYAPP.HeaderCollectionReusableView:0x7fe602031c40 )>",
"<NSLayoutConstraint:0x600000053a20 UIImageView:0x7fe602031e40.trailing == MYAPP.HeaderCollectionReusableView:0x7fe602031c40.trailing   (active)>",
"<NSLayoutConstraint:0x600000050be0 UIImageView:0x7fe602031e40.width == 1024   (active)>",
"<NSLayoutConstraint:0x6000000218b0 'UIView-Encapsulated-Layout-Width' MYAPP.HeaderCollectionReusableView:0x7fe602031c40.width == 1093   (active)>"
)

我知道问题出在 Header 的 imageView 中,但不确定到底是什么。

这些是 header 视图中图像的约束条件:

episodeImageView.anchor(top: topAnchor, leading: leadingAnchor, bottom: nil, trailing: trailingAnchor, size: .init(width: width, height: 0))
episodeImageView.heightAnchor.constraint(equalTo: episodeImageView.widthAnchor, multiplier: 0.65).isActive = true

我正在使用以下扩展程序进行锚定:

extension UIView {
var width: CGFloat {
    return frame.size.width
}

var height: CGFloat {
    return frame.size.height
}

var left: CGFloat {
    return frame.origin.x
}

var right: CGFloat {
    return left + width
}

var top: CGFloat {
    return frame.origin.y
}

var bottom: CGFloat {
    return top + height
}

func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, size: CGSize = .zero) {
    
    translatesAutoresizingMaskIntoConstraints = false
    
    if let top = top {
        topAnchor.constraint(equalTo: top, constant: padding.top).isActive = true
    }
    
    if let leading = leading {
        leadingAnchor.constraint(equalTo: leading, constant: padding.left).isActive = true
    }
    
    if let bottom = bottom {
        bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom).isActive = true
    }
    
    if let trailing = trailing {
        trailingAnchor.constraint(equalTo: trailing, constant: -padding.right).isActive = true
    }
    
    if size.width != 0 {
        widthAnchor.constraint(equalToConstant: size.width).isActive = true
    }
    
    if size.height != 0 {
        heightAnchor.constraint(equalToConstant: size.height).isActive = true
    }
}
}

这些是 collection 视图的约束:

private func setConstraints() {
    var devWidth: CGFloat = 0.0
    if UIDevice.current.orientation.isLandscape {
        devWidth = view.width * 0.8
    } else {
        devWidth = view.height * 0.8
    }
    
    leadingCVAnchor = collectionView?.leadingAnchor.constraint(equalTo: view.leadingAnchor)
    trailingCVAnchor = collectionView?.trailingAnchor.constraint(equalTo: view.trailingAnchor)
    centerCVAnchor = collectionView?.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    widthCVAnchor = collectionView?.widthAnchor.constraint(equalToConstant: devWidth)
    
    collectionView?.translatesAutoresizingMaskIntoConstraints = false
    
    collectionView?.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    collectionView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    leadingCVAnchor?.isActive = true
    trailingCVAnchor?.isActive = true
    
    if UIDevice.current.userInterfaceIdiom == .pad {
        if UIDevice.current.orientation.isLandscape {
            centerCVAnchor?.isActive = true
            widthCVAnchor?.isActive = true
            leadingCVAnchor?.isActive = false
            trailingCVAnchor?.isActive = false
        } else {
            leadingCVAnchor?.isActive = true
            trailingCVAnchor?.isActive = true
        }
    } else {
        leadingCVAnchor?.isActive = true
        trailingCVAnchor?.isActive = true
    }
}

使用此覆盖到 viewWillTransition:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.current.userInterfaceIdiom == .pad {
        if UIDevice.current.orientation.isLandscape {
            print("Orientation Landscape")
            leadingCVAnchor?.isActive = false
            trailingCVAnchor?.isActive = false
            widthCVAnchor?.isActive = true
            centerCVAnchor?.isActive = true
        } else {
            print("Orientation Portrait")
            leadingCVAnchor?.isActive = true
            trailingCVAnchor?.isActive = true
            widthCVAnchor?.isActive = false
            centerCVAnchor?.isActive = false
        }
    }
}

这个项目不使用故事板,一切都在代码中完成。

我对约束还很陌生,所以不确定在哪里解决问题或如何解释 NSLayoutConstraint 警告。

如何解决这个约束问题?

问题是 1024 和 1093 不是同一个数字。你已经限制了宽度,所以它必须是 1024。你还说前缘应该固定到其他视图,后缘也固定到其他视图,这些东西相距 1093。不能两者兼得。