代码锚点布局后ImageView位置异常,部分CollectionViewCell布局错乱
Hey there! Let’s break down what’s causing those wonky layouts in your first and 9th cells, and fix them step by step:
1. Repeated Constraint Activation (The Root Problem)
Your setupUI() method lives inside layoutSubviews(), which gets called over and over again—like when a cell is reused from the collection view’s pool, when the screen rotates, or even when the cell’s content updates. Every time layoutSubviews runs, you’re re-activating the exact same constraints, which creates hidden constraint conflicts. This is why reused cells (like your 1st and 9th ones) end up with broken positioning.
Fix: Setup Constraints Only Once
Move your constraint setup code to a place that runs one time per cell instance, like the cell’s initializer. Also, don’t forget to add your subviews to the cell’s contentView (you missed this critical step!)—it’s the proper container for collection view cell content.
2. Unnecessary sizeToFit() on the Label
Calling sizeToFit() in the label’s lazy initializer does nothing useful here. At that point, the label isn’t attached to a parent view, and your constraints will eventually control its size anyway. Just remove that line.
Corrected Code
private lazy var iconView: UIImageView = { let image = UIImageView() image.translatesAutoresizingMaskIntoConstraints = false image.clipsToBounds = true return image }() private lazy var label: UILabel = { let label = UILabel() label.numberOfLines = 2 label.font = NeoSansPro.regular.of(size: 12) label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false // Removed sizeToFit()—it's redundant here return label }() // Initialize layout once when the cell is created override init(frame: CGRect) { super.init(frame: frame) setupUI() } required init?(coder: NSCoder) { super.init(coder: coder) setupUI() } func setupUI() { // Add subviews to contentView (not directly to the cell!) contentView.addSubview(iconView) contentView.addSubview(label) // Activate constraints a single time NSLayoutConstraint.activate([ iconView.heightAnchor.constraint(equalToConstant: 32), iconView.widthAnchor.constraint(equalToConstant: 32), iconView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), iconView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor, constant: -16), label.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 8), label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4), label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 4), label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -4), ]) } // Keep layoutSubviews only if you need post-layout adjustments (no constraint setup here!) override func layoutSubviews() { super.layoutSubviews() // Example: Add corner radius adjustments here if needed }
Quick Tips to Avoid Future Issues:
- Always use
contentViewas the parent for your cell’s subviews—it handles selection/highlight states and content insets correctly. - Never add or activate constraints inside
layoutSubviews()unless you’re explicitly adjusting them for dynamic layout changes (and even then, make sure you’re not duplicating them). - Reused cells inherit their previous constraints, so duplicate constraint activation is one of the most common causes of layout glitches in collection/table views.
内容的提问来源于stack exchange,提问作者Vadym Marchenko

