CollectionView dynamic height with Swift 3 in iOS

后端 未结 4 1439
说谎
说谎 2020-12-18 06:16

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

相关标签:
4条回答
  • 2020-12-18 06:38

    all what you need to do is making an IBOutlet for the UICollectionView layout, set the estimatedItemSize to any size, in your cell class you have to specify the cell width (if you just want the height to be dynamic and the width is static) and/or height in awakeFromNib and disable translatesAutoresizingMaskIntoConstraintsself.contentView.translatesAutoresizingMaskIntoConstraints = false. so the final result should be something like this

    class ProfileViewController: UIViewController {
        @IBOutlet var collectionView: UICollectionView!
        @IBOutlet var collectionLayout: UICollectionViewFlowLayout!
    
    
        var person: Person!
    
    override func viewDidLoad() {
            super.viewDidLoad()
    
            collectionView.register(UINib(nibName: "ProfileCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "Cell")
            collectionLayout.estimatedItemSize = CGSize(width: screenWidth * 0.4, height: 1)
            collectionView.reloadData()
        }
    
        func numberOfSections(in collectionView: UICollectionView) -> Int {
            return 1
        }
    
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 1
        }
    
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! ProfileCollectionViewCell
    
            return cell
        }
        }
    

    and your cell class should be something like this

    class ProfileCollectionViewCell: UICollectionViewCell {
    @IBOutlet var containerWidthConstraint: NSLayoutConstraint!
     override func awakeFromNib() {
            super.awakeFromNib()
    
            self.contentView.translatesAutoresizingMaskIntoConstraints = false
            containerWidthConstraint.constant = screenWidth - (2 * 12)
        }
        }
    

    and this is a good tutorial for self sizing in ios https://engineering.shopspring.com/dynamic-cell-sizing-in-uicollectionview-fd95f614ef80

    0 讨论(0)
  • 2020-12-18 06:44

    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)          
     }
    
    0 讨论(0)
  • 2020-12-18 06:46

    Provide estimatedSize to your UICollectionViewLayout.

    The estimated size should be the size shown in the size inspector of your xib.

    collectionViewLayout.estimatedItemSize = CGSize(width: collectionView.frame.width, height: 50)
    

    Override the method preferredLayoutAttributesFitting(_:) in your UICollectionViewCell

    override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        setNeedsLayout()
        layoutIfNeeded()
            
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
            
        var frame = layoutAttributes.frame
        frame.size.height = ceil(size.height)
            
        layoutAttributes.frame = frame
            
        return layoutAttributes
    }
    

    Your collection view cell will now have dynamic size as per the content.

    0 讨论(0)
  • 2020-12-18 06:55

    I solved it :)

    I just tried to compute my cell's width and expect height in sizeForItemAt function and it works !

    Code below :

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let imageShowingWidth: CGFloat = self.view.frame.width / CGFloat(self.howManyImageShowing)
    
        let labelName = "@\(self.tweetShowing[indexPath.row].user.screenName) (\(self.tweetShowing[indexPath.row].user.name))"
        let labelNameFont: UIFont = UIFont(name: "PingFangTC-Semibold", size: 16)!
        let labelNameWidth: CGFloat = self.view.frame.width - YourWidthOffSet// (YourWidthOffSet include all images' width and all margins)
        let labelNameHeight: CGFloat = self.getHeightForLable(labelWidth: labelNameWidth, labelText: labelName, labelFont: labelNameFont)
    
        let labelContentFont: UIFont = UIFont(name: "PingFangTC-Regular", size: 16)!
        let labelContentHeight: CGFloat = self.getHeightForLable(labelWidth: labelNameWidth, numberOfLines: 0, labelText: self.tweetShowing[indexPath.row].text, labelFont: labelContentFont)
    
        let cellHeight: CGFloat = labelNameHeight + labelContentHeight + YourHeightOffSet // (YourHeightOffSet means all margins)
    
        return self.typeControl.selectedSegmentIndex == 0 ? CGSize(width: self.view.frame.width, height: cellHeight) : CGSize(width: imageShowingWidth, height: imageShowingWidth)
    }
    
    func getHeightForLable(labelWidth: CGFloat, numberOfLines: Int = 1, labelText: String, labelFont: UIFont) -> CGFloat {
        let tempLabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: labelWidth, height: CGFloat.greatestFiniteMagnitude))
        tempLabel.numberOfLines = numberOfLines
        tempLabel.text = labelText
        tempLabel.font = labelFont
        tempLabel.sizeToFit()
        return tempLabel.frame.height
    }
    
    0 讨论(0)
提交回复
热议问题