Search code examples
iosswiftuicollectionviewuicollectionviewcelluicollectionviewlayout

Horizontal scrolling collection view partially hiding first cell content on initial load


I have a UIView and inside that, I have added a UILabel and UICollectionView. The UICollectionView scrolls horizontally. But the issue is that when I run the app, the UICollectionView offset is set in such a way that the first cell is partly hidden. If I scroll to the right then I can see the contents of the first cell. But when I let go it bounces back to its original hidden state.

As you can see here the first cell has 2 UIViews but only the second one is visible.

sideways hidden cell layout front view of hidden cell

When I scroll right, this is how it looks:

The, I... 10, is the cell that is getting hidden. I have added the elements programmatically, so could be a constraint issue. But I can't zero down on what could be causing it.

Here's my UICollectionViewCell:

class UserCountryCell: UICollectionViewCell {
    
    let countryNameLabel: UILabel
    let countryUserCountLabel: UILabel
    
    
    override init(frame: CGRect) {
        countryNameLabel = UILabel()
        countryUserCountLabel = UILabel()
        super.init(frame: frame)

        self.addSubview(countryNameLabel)
        countryNameLabel.translatesAutoresizingMaskIntoConstraints = false
        countryNameLabel.font = UIFont.boldSystemFont(ofSize: 13)
        countryNameLabel.textColor = .white
        
        self.addSubview(countryUserCountLabel)
        countryUserCountLabel.translatesAutoresizingMaskIntoConstraints = false
        countryUserCountLabel.font = UIFont.systemFont(ofSize: 13)
        countryUserCountLabel.textColor = .white
        
        NSLayoutConstraint.activate([
            countryNameLabel.trailingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
            countryNameLabel.heightAnchor.constraint(equalToConstant: 30),
            countryNameLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5),
            countryNameLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5),
//            countryNameLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0),
            countryNameLabel.widthAnchor.constraint(equalToConstant: 20),

            countryUserCountLabel.leadingAnchor.constraint(equalTo: countryNameLabel.trailingAnchor, constant: 5),
            countryUserCountLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 5),
            countryUserCountLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 5),
            countryUserCountLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -5),
            countryUserCountLabel.heightAnchor.constraint(equalToConstant: 30),
            countryUserCountLabel.widthAnchor.constraint(equalToConstant: 40)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configureCell(countryName: String, countryUserCount: Int) {
        countryNameLabel.text = countryName
        countryUserCountLabel.text = String(countryUserCount)
    }
}

Solution

  • OK - couple things...

    As I said in my comment, add subviews and constraints to the cell's .contentView, not to the cell itself.

    You do have a few mistakes in your constraints. You constrained the countryNameLabel.trailingAnchor to self.leadingAnchor ... that should be .leadingAnchor to .leadingAnchor.

    Your .bottomAnchor constants should be negative.

    If you want the labels' text to determine their widths, don't assign a .widthAnchor.

    Try replacing your init with this:

    override init(frame: CGRect) {
        countryNameLabel = UILabel()
        countryUserCountLabel = UILabel()
        super.init(frame: frame)
        
        contentView.addSubview(countryNameLabel)
        countryNameLabel.translatesAutoresizingMaskIntoConstraints = false
        countryNameLabel.font = UIFont.boldSystemFont(ofSize: 13)
        countryNameLabel.textColor = .white
        
        contentView.addSubview(countryUserCountLabel)
        countryUserCountLabel.translatesAutoresizingMaskIntoConstraints = false
        countryUserCountLabel.font = UIFont.systemFont(ofSize: 13)
        countryUserCountLabel.textColor = .white
        
        NSLayoutConstraint.activate([
    
            // needs to be .leadingAnchor to .leadingAnchor
            //countryNameLabel.trailingAnchor.constraint(equalTo: self.leadingAnchor, constant: 5),
            countryNameLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 5),
    
            countryNameLabel.heightAnchor.constraint(equalToConstant: 30),
            countryNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            countryNameLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
            
            // if you want the label width to fit its text
            //  don't set the label's widthAnchor
            //countryNameLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: 0),
            //countryNameLabel.widthAnchor.constraint(equalToConstant: 20),
            
            countryUserCountLabel.leadingAnchor.constraint(equalTo: countryNameLabel.trailingAnchor, constant: 5),
            countryUserCountLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
            countryUserCountLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
            countryUserCountLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5),
            countryUserCountLabel.heightAnchor.constraint(equalToConstant: 30),
    
            // if you want the label width to fit its text
            //  don't set the label's widthAnchor
            //countryUserCountLabel.widthAnchor.constraint(equalToConstant: 40)
        ])
    
    }