Search code examples
iosdynamicswift3uicollectionviewautolayout

CollectionView dynamic height with Swift 3 in iOS


Recently, I'm trying to do some projects for practicing. So I watched the course "Developing Apps for iOS", Stanford University, CS193P, 2017.

And now, I'm doing "Smashtag" project but I have some problems in it. I want to use a CollectionView with two UICollectionViewFlowLayout to show two types in each xib (one is like tableView, another is showing a image in square) of CollectionView by SegmentedControl.

My problems below :

  1. How to make CollectionViewCell showing in dynamic height just like TableView's UITableViewAutomaticDimension?

    And this is what I just tried below :

    I tried to make CollectionView's autoResize setting as like TableView's autoDimension with using UICollectionViewFlowLayoutAutomaticSize. ( @available(iOS 10.0, *) )

enum CollectionViewType {
  case tweet
  case image
}

// MARK: - Decide What Kind Of FlowLayout
func decideFlowLayout(type: CollectionViewType) -> UICollectionViewFlowLayout {

    // just for .image type
    var howManyImageShowing = 3  
    var imageShowingWidth: Double {
        return Double(self.view.frame.width) / Double(howManyImageShowing)
    }

    // .tweet is a type showing like TableViewCell -> this make me confused !!
    // another type is just showing a image in square -> I have no problem here
    let estimatedItemSize = type == .tweet ? CGSize(width: self.view.frame.width, height: 155.0) :
                                                CGSize(width: imageShowingWidth, height: imageShowingWidth)

    let collectionViewLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
    collectionViewLayout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

    // --------- Make this setting as TableView does --------- 
    // ------------ Somethis just like this below ------------
    /*
        tableView.estimatedRowHeight = 155.0
        tableView.rowHeight = UITableViewAutomaticDimension
    */

    collectionViewLayout.estimatedItemSize = estimatedItemSize
    collectionViewLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize
    // ------------------------------------------------------- 

    collectionViewLayout.minimumLineSpacing = 0
    collectionViewLayout.minimumInteritemSpacing = 0

    return collectionViewLayout
}

Constraint of my CollectionViewCell xib here : enter image description here But it has bug when I run this app

I don't know what I miss or misunderstand. enter image description here

  1. Why this solution will work ?

    I already search so many solutions of this problem in Stack Overflow but I just find this and make me really confused :(

    This solution give the view a Width Constraint which is in CollectionViewCell xib and set this constraint's constant a value and it works! I can not configure out why Width Constraint will make the cell's height in dynamic? This make me really confused, I think this is weird...

    https://github.com/tttsunny/CollectionViewAutoSizingTest

class Cell: UICollectionViewCell {
    @IBOutlet weak var headerLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var widthConstraint: NSLayoutConstraint!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
        let screenWidth = UIScreen.main.bounds.size.width
        widthConstraint.constant = screenWidth - (2 * 12)
    }
}
  1. How to do CollectionViewCell dynamic height without using UICollectionViewFlowLayoutAutomaticSize. ( @available(iOS 10.0, *) ) ?

    Because I want to handle different iOS Versions not only in iOS 10 but also below iOS 10.

I really want to be pro in iOS development and a great developer but I'm still learning and trying. Any replies I will be greatly appreciated.

Thank you !!


Solution

  • Use the following code to change the height according to the text displayed:

     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        return CGSizeMake(view.frame.width , 64)
    }
    override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    {
      let approximateWidthOfContent = view.frame.width - x
        // x is the width of the logo in the left 
    
      let size = CGSize(width: approximateWidthOfContent, height: 1000)
    
      //1000 is the large arbitrary values which should be taken in case of very high amount of content 
    
     let attributes = [NSFontAttributeName: UIFont.systemFont(ofSize: 15)]            
     let estimatedFrame = NSString(string: user.bioText).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
     return CGSize(width: view.frame.width, height: estimatedFrame.height + 66)          
     }