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。不能两者兼得。
我有一个 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。不能两者兼得。