不滚动

时间:2017-08-06 21:14:41

标签: ios swift swift3 uicollectionview uicollectionviewlayout

我正在尝试创建一个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比它在模拟器中实际显示的“更高”。

The bottom row is chopped in half vertically

UICollectionView中有什么东西可以给我可见的大小吗?我在布局时间方面处于错误的时间,还是应该在某个时候添加另一种使大小无效的方法?

我没有找到任何有关显示所有项目的集合视图的教程,并且没有垂直滚动,因此任何其他指针(甚至是执行此类操作的库)都将非常感激。

谢谢!

4 个答案:

答案 0 :(得分:1)

对于版面尺寸,您可以使用UICollectionViewFlowLayout并根据屏幕宽度和高度关联尺寸,以便保留UICollectionView.的网格样式外观:https://developer.apple.com/documentation/uikit/uicollectionviewflowlayouthttps://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)
      }
  }

标出正确值的差异,在您的情况下,该差异将是行的最低值。