在 iOS 中使用 Swift 3 的 CollectionView 动态高度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45204283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CollectionView dynamic height with Swift 3 in iOS
提问by Kevin
Recently, I'm trying to do some projects for practicing. So I watched the course "Developing Apps for iOS", Stanford University, CS193P, 2017.
最近,我正在尝试做一些项目来练习。所以我看了课程“Developing Apps for iOS”,斯坦福大学,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.
现在,我正在做“Smashtag”项目,但我在其中遇到了一些问题。我想使用带有两个 UICollectionViewFlowLayout 的 CollectionView 来通过 SegmentedControl 在 CollectionView 的每个 xib 中显示两种类型(一种类似于 tableView,另一种是在方形中显示图像)。
My problems below :
我的问题如下:
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, *) )
如何让 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
}
Constraint of my CollectionViewCell xib here :
But it has bug when I run this app
我的 CollectionViewCell xib 的约束在这里:
但是当我运行这个应用程序时它有错误
I don't know what I miss or misunderstand.
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 Constraintwhich is in CollectionViewCell xib and set this constraint's constant a value and it works! I can not configure out why Width Constraintwill make the cell's height in dynamic? This make me really confused, I think this is weird...
为什么这个解决方案会起作用?
我已经在 Stack Overflow 中搜索了很多这个问题的解决方案,但我只是找到了这个,让我真的很困惑:(
此解决方案为视图提供了一个位于 CollectionViewCell xib 中的宽度约束,并将此约束的常量设置为一个值,并且它可以工作!我无法配置为什么宽度约束会使单元格的高度动态?这让我真的很困惑,我觉得这很奇怪......
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)
}
}
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.
如何在不使用UICollectionViewFlowLayoutAutomaticSize 的情况下做 CollectionViewCell 动态高度。(@available(iOS 10.0,*))?
因为我不仅要在 iOS 10 中处理不同的 iOS 版本,还要在 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.
我真的很想成为 iOS 开发的专业人士和优秀的开发人员,但我仍在学习和尝试。任何答复我将不胜感激。
Thank you !!
谢谢 !!
采纳答案by Samarth Kejriwal
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)
}
回答by Kevin
I solved it :)
我解决了:)
I just tried to compute my cell's width and expect height in sizeForItemAt function and it works !
我只是试图计算我的单元格的宽度并期望在 sizeForItemAt 函数中获得高度并且它有效!
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
}
回答by Eslam Eslam Nour
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
您需要做的就是为 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
}
}
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
这是在 ios 中自我调整大小的好教程 https://engineering.shopspring.com/dynamic-cell-sizing-in-uicollectionview-fd95f614ef80
回答by Atul Pol
Provide
estimatedSize
to yourUICollectionViewLayout
.The estimated size should be the size shown in the size inspector of your xib.
提供
estimatedSize
给您的UICollectionViewLayout
.估计尺寸应该是您的 xib 尺寸检查器中显示的尺寸。
collectionViewLayout.estimatedItemSize = CGSize(width: collectionView.frame.width, height: 50)
Override the method
preferredLayoutAttributesFitting(_:)
in yourUICollectionViewCell
覆盖
preferredLayoutAttributesFitting(_:)
你的方法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.
您的集合视图单元格现在将根据内容具有动态大小。