在iOS中使用Swift 3的CollectionView动态高度

最近,我正在尝试做一些练习项目。 所以我看了“开发iOS应用程序”课程,斯坦福大学,CS193P,2017。

现在,我正在做“Smashtag”项目,但我遇到了一些问题。 我想使用带有两个UICollectionViewFlowLayout的CollectionView,通过SegmentedControl在每个xib中显示两个类型(一个像tableView,另一个在方块中显示图像)。

我的问题如下:

  1. 如何使CollectionViewCell显示在动态高度,就像TableView的UITableViewAutomaticDimension一样?

    这就是我刚才尝试的内容:

    我尝试使用UICollectionViewFlowLayoutAutomaticSize使CollectionView的autoResize设置像TableView的autoDimension 一样。 (@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 } 

这里我的CollectionViewCell xib的约束: 在此处输入图像描述 但是当我运行这个应用程序时它有bug

我不知道我想念或误解了什么。 在此处输入图像描述

  1. 为什么这个解决方案有效?

    我已经在Stack Overflow中搜索了这个问题的这么多解决方案,但我发现这个并让我真的很困惑:(

    此解决方案为视图提供了一个宽度约束 ,该约束位于CollectionViewCell xib中,并将此约束的常量设置为值,并且它可以正常工作! 我无法配置为什么Width Constraint会使单元格的高度处于动态状态? 这让我很困惑,我觉得这很奇怪……

    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. 如何在不使用UICollectionViewFlowLayoutAutomaticSize的情况下进行CollectionViewCell动态高度 (@available(iOS 10.0,*))

    因为我不仅要在iOS 10中处理不同的iOS版本,还要在iOS 10以下处理。

我真的想成为iOS开发专业人士和优秀的开发人员,但我还在学习和尝试。 任何回复我将不胜感激。

谢谢 !!

使用以下代码根据显示的文本更改高度:

  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) } 

我解决了:)

我只是试图计算我的单元格的宽度,并期望sizeForItemAt函数的高度,它的工作原理!

代码如下:

 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 } 

所有你需要做的就是为UICollectionView布局制作一个IBOutlet,将estimatedItemSize设置为任何大小,在你的单元类中你必须指定单元格宽度(如果你只想要高度是动态的,宽度是静态的)和/或awakeFromNib高度并禁用translatesAutoresizingMaskIntoConstraints self.contentView.translatesAutoresizingMaskIntoConstraints = false 。 所以最终的结果应该是这样的

 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 } } 

你的细胞类应该是这样的

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

这是ios中自我resize的好教程https://engineering.shopspring.com/dynamic-cell-sizing-in-uicollectionview-fd95f614ef80