Asked  7 Months ago    Answers:  5   Viewed   45 times

I'm trying to get self sizing UICollectionViewCells working with Auto Layout, but I can't seem to get the cells to size themselves to the content. I'm having trouble understanding how the cell's size is updated from the contents of what's inside the cell's contentView.

Here's the setup I've tried:

  • Custom UICollectionViewCell with a UITextView in its contentView.
  • Scrolling for the UITextView is disabled.
  • The contentView's horizontal constraint is: "H:|[_textView(320)]", i.e. the UITextView is pinned to the left of the cell with an explicit width of 320.
  • The contentView's vertical constraint is: "V:|-0-[_textView]", i.e. the UITextView pinned to the top of the cell.
  • The UITextView has a height constraint set to a constant which the UITextView reports will fit the text.

Here's what it looks like with the cell background set to red, and the UITextView background set to Blue: cell background red, UITextView background blue

I put the project that I've been playing with on GitHub here.

 Answers

74

Updated for Swift 5

preferredLayoutAttributesFittingAttributes renamed to preferredLayoutAttributesFitting and use auto sizing


Updated for Swift 4

systemLayoutSizeFittingSize renamed to systemLayoutSizeFitting


Updated for iOS 9

After seeing my GitHub solution break under iOS 9 I finally got the time to investigate the issue fully. I have now updated the repo to include several examples of different configurations for self sizing cells. My conclusion is that self sizing cells are great in theory but messy in practice. A word of caution when proceeding with self sizing cells.

TL;DR

Check out my GitHub project


Self sizing cells are only supported with flow layout so make sure thats what you are using.

There are two things you need to setup for self sizing cells to work.

1. Set estimatedItemSize on UICollectionViewFlowLayout

Flow layout will become dynamic in nature once you set the estimatedItemSize property.

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

2. Add support for sizing on your cell subclass

This comes in 2 flavours; Auto-Layout or custom override of preferredLayoutAttributesFittingAttributes.

Create and configure cells with Auto Layout

I won't go to in to detail about this as there's a brilliant SO post about configuring constraints for a cell. Just be wary that Xcode 6 broke a bunch of stuff with iOS 7 so, if you support iOS 7, you will need to do stuff like ensure the autoresizingMask is set on the cell's contentView and that the contentView's bounds is set as the cell's bounds when the cell is loaded (i.e. awakeFromNib).

Things you do need to be aware of is that your cell needs to be more seriously constrained than a Table View Cell. For instance, if you want your width to be dynamic then your cell needs a height constraint. Likewise, if you want the height to be dynamic then you will need a width constraint to your cell.

Implement preferredLayoutAttributesFittingAttributes in your custom cell

When this function is called your view has already been configured with content (i.e. cellForItem has been called). Assuming your constraints have been appropriately set you could have an implementation like this:

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    //Exhibit A - We need to cache our calculation to prevent a crash.
    if !isHeightCalculated {
        setNeedsLayout()
        layoutIfNeeded()
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = CGFloat(ceilf(Float(size.width)))
        layoutAttributes.frame = newFrame
        isHeightCalculated = true
    }
    return layoutAttributes
}

NOTE On iOS 9 the behaviour changed a bit that could cause crashes on your implementation if you are not careful (See more here). When you implement preferredLayoutAttributesFittingAttributes you need to ensure that you only change the frame of your layout attributes once. If you don't do this the layout will call your implementation indefinitely and eventually crash. One solution is to cache the calculated size in your cell and invalidate this anytime you reuse the cell or change its content as I have done with the isHeightCalculated property.

Experience your layout

At this point you should have 'functioning' dynamic cells in your collectionView. I haven't yet found the out-of-the box solution sufficient during my tests so feel free to comment if you have. It still feels like UITableView wins the battle for dynamic sizing IMHO.

Caveats

Be very mindful that if you are using prototype cells to calculate the estimatedItemSize - this will break if your XIB uses size classes. The reason for this is that when you load your cell from a XIB its size class will be configured with Undefined. This will only be broken on iOS 8 and up since on iOS 7 the size class will be loaded based on the device (iPad = Regular-Any, iPhone = Compact-Any). You can either set the estimatedItemSize without loading the XIB, or you can load the cell from the XIB, add it to the collectionView (this will set the traitCollection), perform the layout, and then remove it from the superview. Alternatively you could also make your cell override the traitCollection getter and return the appropriate traits. It's up to you.

Let me know if I missed anything, hope I helped and good luck coding


Tuesday, June 1, 2021
 
muffe
answered 7 Months ago
58

1. Solution for iOS 13+

With Swift 5.1 and iOS 13, you can use Compositional Layout objects in order to solve your problem.

The following complete sample code shows how to display multiline UILabel inside full-width UICollectionViewCell:

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let items = [
        [
            "Lorem ipsum dolor sit amet.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            "Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
        ]
    ]

    override func viewDidLoad() {
        super.viewDidLoad()

        let size = NSCollectionLayoutSize(
            widthDimension: NSCollectionLayoutDimension.fractionalWidth(1),
            heightDimension: NSCollectionLayoutDimension.estimated(44)
        )
        let item = NSCollectionLayoutItem(layoutSize: size)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)

        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
        section.interGroupSpacing = 10

        let headerFooterSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .absolute(40)
        )
        let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
            layoutSize: headerFooterSize,
            elementKind: "SectionHeaderElementKind",
            alignment: .top
        )
        section.boundarySupplementaryItems = [sectionHeader]

        let layout = UICollectionViewCompositionalLayout(section: section)
        collectionView.collectionViewLayout = layout
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
        collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return items.count
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items[section].count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
        cell.label.text = items[indexPath.section][indexPath.row]
        return cell
    }

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
        headerView.label.text = "Header"
        return headerView
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition: { context in
            self.collectionView.collectionViewLayout.invalidateLayout()
        }, completion: nil)
    }

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .magenta

        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        label.numberOfLines = 0
        backgroundColor = .orange
        contentView.addSubview(label)

        label.translatesAutoresizingMaskIntoConstraints = false
        label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

Expected display:

enter image description here


2. Solution for iOS 11+

With Swift 5.1 and iOS 11, you can subclass UICollectionViewFlowLayout and set its estimatedItemSize property to UICollectionViewFlowLayout.automaticSize (this tells the system that you want to deal with autoresizing UICollectionViewCells). You'll then have to override layoutAttributesForElements(in:) and layoutAttributesForItem(at:) in order to set cells width. Lastly, you'll have to override your cell's preferredLayoutAttributesFitting(_:) method and compute its height.

The following complete code shows how to display multiline UILabel inside full-width UIcollectionViewCell (constrained by UICollectionView's safe area and UICollectionViewFlowLayout's insets):

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

    let items = [
        [
            "Lorem ipsum dolor sit amet.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
        ],
        [
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
            "Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
        ]
    ]
    let customFlowLayout = CustomFlowLayout()

    override func viewDidLoad() {
        super.viewDidLoad()

        customFlowLayout.sectionInsetReference = .fromContentInset // .fromContentInset is default
        customFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        customFlowLayout.minimumInteritemSpacing = 10
        customFlowLayout.minimumLineSpacing = 10
        customFlowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        customFlowLayout.headerReferenceSize = CGSize(width: 0, height: 40)

        collectionView.collectionViewLayout = customFlowLayout
        collectionView.contentInsetAdjustmentBehavior = .always
        collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
        collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return items.count
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items[section].count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
        cell.label.text = items[indexPath.section][indexPath.row]
        return cell
    }

    override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
        headerView.label.text = "Header"
        return headerView
    }

}

CustomFlowLayout.swift

import UIKit

final class CustomFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes]
        layoutAttributesObjects?.forEach({ layoutAttributes in
            if layoutAttributes.representedElementCategory == .cell {
                if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame {
                    layoutAttributes.frame = newFrame
                }
            }
        })
        return layoutAttributesObjects
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let collectionView = collectionView else {
            fatalError()
        }
        guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
            return nil
        }

        layoutAttributes.frame.origin.x = sectionInset.left
        layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
        return layoutAttributes
    }

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .magenta

        addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        label.numberOfLines = 0
        backgroundColor = .orange
        contentView.addSubview(label)

        label.translatesAutoresizingMaskIntoConstraints = false
        label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
        layoutIfNeeded()
        layoutAttributes.frame.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
        return layoutAttributes
    }

}

Here are some alternative implementations for preferredLayoutAttributesFitting(_:):

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
    layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
    return layoutAttributes
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    label.preferredMaxLayoutWidth = layoutAttributes.frame.width
    layoutAttributes.frame.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
    return layoutAttributes
}

Expected display:

enter image description here

Wednesday, June 2, 2021
 
subroutines
answered 6 Months ago
11

Update 2:
It turns out that this answer is not correct. Please see the answer below or by clicking this link https://stackoverflow.com/a/20147799/814389 instead.


Update

So I have revisited this answer since as I have found out a little more about this bug..

I grabbed all the devices I had available to me and ran the same tests on each one and these were the results:

DEVICE          OS Version      CELL REUSE
=============   =============   =============
iPad 4          7.0.0           YES
iPad 4          7.0.3           YES
iPad 3          7.0.3           NO
iPad 2          7.0.3           NO
iPad Mini       7.0.0           YES
iPad Mini       7.0.3           YES
iPhone 5s       7.0.3           YES
iPhone 4        7.0.2           YES
iPhone 4        7.0.3           YES

As you can see, it looks like for some reason cell reuse is not working on older iPads (ones that aren't capable of rendering the blurs).

I initially thought that Apple may have just prevented reuse on older iPads due to some sort of performance issue but if that was to have made sense, the iPhone 4 would also show the same results.

To get around this issue in my application, I have a NSMutableDictionary in my collectionViewController and I am storing my cells in there with the key being the indexPath.. In my case this is OK as I only have around 9 cells and their indexPaths never change but if you needed something more flexible then maybe it would be a good idea to checkout PSTCollectionView (https://github.com/steipete/PSTCollectionView)


Just tested this out on a physical device.. and it seems to work fine on both iOS 7 and 6 but not iOS 7 Simulator!!!

Just put some logs in the collectionView sample:

@implementation Cell

- (id)initWithCoder:(NSCoder *)aDecoder
{
    NSLog(@"%s",__func__);
    self = [super initWithCoder:aDecoder];
    if (self)
    {
        CustomCellBackground *backgroundView = [[CustomCellBackground alloc] initWithFrame:CGRectZero];
        self.selectedBackgroundView = backgroundView;
    }
    return self;
}

-(void)prepareForReuse
{
    NSLog(@"%s",__func__);
}

-(void)dealloc
{
    NSLog(@"%s",__func__);
}

@end

Then scrolled to the bottom on all three devices and this was the output:

iOS 7 Simulator

2013-10-09 17:42:45.798 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.807 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.811 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.841 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.844 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.848 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.852 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:45.857 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.080 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.083 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.181 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.183 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.208 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.208 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.214 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.218 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.245 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.246 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.264 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.268 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.289 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.290 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.317 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.322 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.343 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.344 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.364 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.367 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.401 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.402 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.430 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.432 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.472 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.472 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.498 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.505 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.561 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.562 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.585 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.587 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.624 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.624 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.669 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.674 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.797 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.799 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.809 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.809 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.810 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.810 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.964 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.966 CollViewSmpl[9547:a0b] -[Cell initWithCoder:]
2013-10-09 17:42:47.987 CollViewSmpl[9547:a0b] -[Cell dealloc]
2013-10-09 17:42:47.987 CollViewSmpl[9547:a0b] -[Cell dealloc]

iOS 6 Device (iPhone 5)

2013-10-09 17:45:42.173 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.191 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.205 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.217 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.230 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.242 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.253 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:42.264 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:43.630 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:43.640 CollViewSmpl[187:907] -[Cell initWithCoder:]
2013-10-09 17:45:43.697 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.706 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.777 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.791 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.844 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.855 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.927 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:43.937 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.027 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.037 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.144 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.155 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.311 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.324 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.560 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:44.571 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.027 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.040 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.397 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.407 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.494 CollViewSmpl[187:907] -[Cell prepareForReuse]
2013-10-09 17:45:45.503 CollViewSmpl[187:907] -[Cell prepareForReuse]

iOS 7 Device (iPhone 5s)

2013-10-09 17:44:37.603 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.015 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.029 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.037 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.045 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.053 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.061 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:38.071 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:39.470 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:39.483 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:39.535 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.540 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.583 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.587 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.633 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.637 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.683 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.688 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.733 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.737 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.783 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:39.791 CollViewSmpl[871:60b] -[Cell initWithCoder:]
2013-10-09 17:44:39.866 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.870 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.933 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:39.938 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.033 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.036 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.149 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.152 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.300 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.304 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.650 CollViewSmpl[871:60b] -[Cell prepareForReuse]
2013-10-09 17:44:40.652 CollViewSmpl[871:60b] -[Cell prepareForReuse]

You can tell that there have been some changes between reuse in iOS 6 and 7 because 1) It doesn't work in the simulator and 2) If you do a really fast scroll to begin with, the cells aren't initially ready for reuse so it has to create a new one to compensate where iOS 6 didn't (see my logs).

There goes half of my day trying to fix a bug that only happens on the simulator.

Friday, July 16, 2021
 
turik
answered 5 Months ago
24

I'm not sure why it's happening. Here's another solution to this problem. Set up a height constraint on UICollectionView object. Then set its constant to be equal to self.collectionView.contentSize.height. I use a similar approach in my app, though I've got UITextView instead of UICollectionView.

UPDATE: I've found a way to do this with intrinsicContentSize: UITextView in UIScrollView using auto layout

Monday, October 4, 2021
 
Ali
answered 2 Months ago
Ali
63

I just tried this in iOS 10/XCode 8 (same results in iOS 9/XCode 7) with the different cell types and it looks like it's possible ONLY for the textLabel and not for the detailTextLabel.

(basically repeating the issue that the OP mentioned)

ViewController code that sets some text alternately on detailTextLabel and textLabel.

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 44
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        if indexPath.row % 2 == 0 {
            cell.textLabel?.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
            cell.detailTextLabel?.text = "<- textLabel"
        } else {
            cell.textLabel?.text = "detailTextLabel ->"
            cell.detailTextLabel?.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
        }
        return cell
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

}

Make sure you set the textLabel and textDetailLabel's line property to 0 and here are the results.

Basic Cell enter image description here

Right Detail Cell enter image description here

Left Detail Cell enter image description here

Subtitle Cell enter image description here

I'll report this as a bug.

Sunday, October 10, 2021
 
Ethunxxx
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share