0

I have an iOS view consisting of a collectionView with a headerView. The view displays fine, but when I rotate the device (iPad), the header elements get duplicated and don't fit correctly. The output window shows the following

(
"<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)>"
)

I understand that the issue is in the imageView within the Header but not sure exactly what it is.

These are the constraints for the image in the header view:

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

I'm using the following extension for anchoring:

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
    }
}
}

And these are the constraints for the collection view:

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
    }
}

with this override to 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
        }
    }
}

This project does not use storyboards, everything is done in code.

I'm fairly new with constraints so not sure where to fix the problem or how to interpret the NSLayoutConstraint warnings.

How can I solve this constraint issue?

1 Answer 1

0

The problem is that 1024 and 1093 aren't the same number. You've constrained the width so that it must be 1024. You also say the leading edge should be pinned to some other view and the trailing edge also pinned to some other view, those things are 1093 apart. Can't have both.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I identified the error taking that in mind and I'm not getting the error anymore. However, the header elements are still getting duplicated. I believe this is being caused by something else entirely.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.