2017-08-06 129 views
1

我试图创建一个UICollectionView,所有单元格100%可见,这样我就不需要滚动来查看它们。我目前正在尝试显示一个3x3的网格,并在运行中计算单元格的大小。UICollectionView不滚动

我有一个容器视图中的标题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行的一半左右被遮蔽的,因为它看起来像框架尺寸为“高”比实际显示在模拟器。

The bottom row is chopped in half vertically

有什么在UICollectionView这会给我的可见大小?我在布局时间方面错误的时间,还是应该添加另一种方法,在某些时候使尺寸无效?

我还没有找到任何教程显示所有项目的集合视图,并且不垂直滚动,所以任何其他指针(甚至是类似这样的库)都将不胜感激。

谢谢!

+0

,它必须得到一个UICollectionView?基于你的描述你想要什么我想你会更好使用嵌套StackViews – TMin

+0

你应该使用集合视图中的节标题;) – John

回答

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

Dude。DUDE。网格布局是第一次尝试 - 你写了那个,还是你找到它的地方?如果你写了它,我欠你一瓶啤酒,如果你找到它,你能指点我到哪里 – Hoopes

+0

此外,代码确实被调用,我有所有的类设置正确,我只是想不通为什么'collectionView.bounds.size'和/或'collectionView .frame.size'没有给我正确的高度。 – Hoopes

+0

你是什么意思,如果它是将在一个单一的屏幕上?我想在某个时候用箭头按钮实现分页,我是否将自己绘制到网格布局的角落? – Hoopes

1

对于版面大小,你可以使用UICollectionViewFlowLayout和涉及的尺寸在屏幕宽度和高度的条款,以保护UICollectionView.见的网格样式的外观:https://developer.apple.com/documentation/uikit/uicollectionviewflowlayouthttps://www.raywenderlich.com/136159/uicollectionview-tutorial-getting-started

至于滚动问题,请检查您的滚动功能是否启用,您的约束设置是否正确,并且您没有在此链接中提到的问题。 UICollectionView does not scroll

祝你好运! :)

+0

嗨,我很抱歉,我不是更清楚。我实际上并不想要滚动视图 - 我想要在屏幕上显示所有内容(全尺寸),所以我不必滚动。我原本是通过嵌套堆栈视图来完成这项工作的,但收集视图的灵活性似乎很有吸引力(我喜欢ios编程两周,fwiw) – Hoopes

1

您滚动不工作,因为视图是屏幕的只是大小...

只是为了让招加1000的偏移的CollectionView的总高度的量是每row *(row.size.height + padding)。

+0

嗨,John,谢谢你的回应。我关闭了滚动 - 我想查看集合视图中的所有单元而不滚动。在截图中,你可以看到最后一行被切断,我试图找出原因(我花了一整天的时间想弄清楚为什么'collectionView.frame'高度不正确 - 我很确定我的数学是 – Hoopes

+0

我不能在接下来的几个小时来检查,但你应该打印你的阀值得到的错误,我同意数学似乎罚款。我会做的第一件事是使用self.view和从尺寸...我将会在以后检查 – John