我正在尝试创建一个100%可见的所有单元格的UICollectionView,这样我就不需要滚动来查看它们了。我正在尝试显示3x3网格,并在运行中计算单元格的大小。
我在容器视图中有一个CollectionView和一个UIView用于标题。标题固定在容器顶部,高度为100px。 CollectionView位于其下方,固定在每一侧,底部,顶部固定在标题的底部。
当我使用sizeForItemAt时,我试图找到可见区域的大小,将其分成1/3大小的块(旁边填充/插入)。我的代码如下:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let numRows = self.numRows()
let itemsPerRow = self.itemsPerRow()
// let frameSize = collectionView.frame.size
let frameSize = collectionView.bounds.size
// let frameSize = collectionView.collectionViewLayout.collectionViewContentSize
// let frameSize = collectionView.intrinsicContentSize
let totalItemPadding = self.itemPadding * (itemsPerRow - 1)
let totalLinePadding = self.linePadding * (numRows - 1)
let availableWidth = frameSize.width - totalItemPadding
var widthPerItem = availableWidth / itemsPerRow
let availableHeight = frameSize.height - totalLinePadding
var heightPerItem = availableHeight / numRows
return CGSize(width: widthPerItem, height: heightPerItem)
}
结果总是第3行大约有一半被遮挡,因为看起来frameSize比它在模拟器中实际显示的“更高”。
UICollectionView中有什么东西可以给我可见的大小吗?我在布局时间方面处于错误的时间,还是应该在某个时候添加另一种使大小无效的方法?
我没有找到任何有关显示所有项目的集合视图的教程,并且没有垂直滚动,因此任何其他指针(甚至是执行此类操作的库)都将非常感激。
谢谢!
答案 0 :(得分:1)
对于版面尺寸,您可以使用UICollectionViewFlowLayout
并根据屏幕宽度和高度关联尺寸,以便保留UICollectionView.
的网格样式外观:https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout和https://www.raywenderlich.com/136159/uicollectionview-tutorial-getting-started。
至于滚动问题,请检查您的滚动是否已启用,约束是否设置正确,并且您没有遇到此链接中提到的问题。 UICollectionView does not scroll
祝你好运! :)答案 1 :(得分:1)
您的滚动无效,因为视图只是屏幕的大小......
只是为了获得技巧,添加1000的偏移量.collectionView的总高度量是每行*(row.size.height + padding)。
答案 2 :(得分:1)
你确定这个方法被调用了吗?在此例程中添加日志语句或断点,并确保它被调用。
如果你忽略了正式声明你的视图控制器符合UICollectionViewDelegateFlowLayout
,那么一个阻止它被调用的常见问题就是。在这种情况下,它将使用它在故事板中找到的任何内容。但是当我这样做时,你的代码对我来说很好,例如:
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let numRows = self.numRows()
let itemsPerRow = self.itemsPerRow()
let frameSize = collectionView.bounds.size
let layout = collectionViewLayout as! UICollectionViewFlowLayout
let totalItemPadding = layout.minimumInteritemSpacing * (itemsPerRow - 1)
let totalLinePadding = layout.minimumInteritemSpacing * (numRows - 1)
let availableWidth = frameSize.width - totalItemPadding
let widthPerItem = availableWidth / itemsPerRow
let availableHeight = frameSize.height - totalLinePadding
let heightPerItem = availableHeight / numRows
return CGSize(width: widthPerItem, height: heightPerItem)
}
}
注意,我也使用了minimumInteritemSpacing
,因此我使用现有的间距参数而不是定义自己的间距参数。使用现有参数(尤其是您也可以在IB中设置的参数)对我来说更好。
顺便说一句,如果它总是在单个屏幕上,则替代方法是使用您自己的自定义布局,而不是流布局。这样你就不会使用大量繁琐的代码来纠缠集合视图的委托。它会更加可重复使用。例如:
class GridLayout: UICollectionViewLayout {
var itemSpacing: CGFloat = 5
var rowSpacing: CGFloat = 5
private var itemSize: CGSize!
private var numberOfRows: Int!
private var numberOfColumns: Int!
override func prepare() {
super.prepare()
let count = collectionView!.numberOfItems(inSection: 0)
numberOfColumns = Int(ceil(sqrt(Double(count))))
numberOfRows = Int(ceil(Double(count) / Double(numberOfColumns)))
let width = (collectionView!.bounds.width - (itemSpacing * CGFloat(numberOfColumns - 1))) / CGFloat(numberOfColumns)
let height = (collectionView!.bounds.height - (rowSpacing * CGFloat(numberOfRows - 1))) / CGFloat(numberOfRows)
itemSize = CGSize(width: width, height: height)
}
override var collectionViewContentSize: CGSize {
return collectionView!.bounds.size
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.center = centerForItem(at: indexPath)
attributes.size = itemSize
return attributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return (0 ..< collectionView!.numberOfItems(inSection: 0)).map { IndexPath(item: $0, section: 0) }
.flatMap { layoutAttributesForItem(at: $0) }
}
private func centerForItem(at indexPath: IndexPath) -> CGPoint {
let row = indexPath.item / numberOfColumns
let col = indexPath.item - row * numberOfColumns
return CGPoint(x: CGFloat(col) * (itemSize.width + itemSpacing) + itemSize.width / 2,
y: CGFloat(row) * (itemSize.height + rowSpacing) + itemSize.height / 2)
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
然后,在视图控制器中:
override func viewDidLoad() {
super.viewDidLoad()
let layout = GridLayout()
layout.itemSpacing = 10
layout.rowSpacing = 5
collectionView?.collectionViewLayout = layout
}
答案 3 :(得分:0)
就我而言,这要简单得多,基本思想是在集合视图的末尾添加额外的填充。在我的情况下,我的方向是水平的,但垂直方向也应如此(尚未测试过该方向),诀窍是如下调整委托函数:
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.init(top: collectionView.bounds.width * 0.02, left: collectionView.bounds.width * 0.02, bottom: collectionView.bounds.width * 0.02, right: collectionView.bounds.width * 0.22)
}
}
标出正确值的差异,在您的情况下,该差异将是行的最低值。