【问题标题】:Resizing UICollectionView with Custom Layout after deleting cells删除单元格后使用自定义布局调整 UICollectionView 的大小
【发布时间】:2018-05-29 00:42:48
【问题描述】:

我从 https://www.raywenderlich.com/164608/uicollectionview-custom-layout-tutorial-pinterest-2 为我的 CollectionView 下载了这个 Pintrest-esc 自定义布局(修改了一点缓存代码)

所以布局工作正常,我进行了设置,所以当您滚动到底部时,我会进行另一个 API 调用,创建并填充其他单元格。

问题:如果用户向下滚动并加载更多单元格(比如说 20 个),然后使用 “搜索功能” 我已在顶部实施,然后它将通过 MinRange - MaxRange 中的价格过滤一些数据(让您说 5 个结果),从而删除一些单元格并重新填充这些单元格。 但是 - 前 20 个单元格存在的所有空间和可滚动空间仍然作为空白空间存在...... 我怎样才能删除这个空间? 为什么可以添加更多单元格时调整大小,但在删除它们时不调整?

我的 API 调用代码:

DispatchQueue.global(qos: .background).async {

        WebserviceController.GetSearchPage(parameters: params) { (success, data) in
            if success
            {

                if let products = data!["MESSAGE"] as? [[String : AnyObject]]
                {
                    self.productList = products

                }
            }

            DispatchQueue.main.async(execute: { () -> Void in
                self.pintrestCollectionView.reloadData()
          self.pintrestCollectionView.collectionViewLayout.invalidateLayout()
                self.pintrestCollectionView.layoutSubviews()
            })

        }

    }

自定义布局类和协议代码:

协议 PinterestLayoutDelegate: 类 {

func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat

}

类 PintrestLayout: UICollectionViewFlowLayout {

// 1

weak var delegate : PinterestLayoutDelegate!

// 2
fileprivate var numberOfColumns = 2
fileprivate var cellPadding: CGFloat = 10

// 3
fileprivate var cache = [UICollectionViewLayoutAttributes]()

// 4
fileprivate var contentHeight: CGFloat = 0

fileprivate var contentWidth: CGFloat {

    guard let collectionView = collectionView else {
        return 0
    }
    let insets = collectionView.contentInset
    return collectionView.bounds.width - (insets.left + insets.right)
}

// 5
override var collectionViewContentSize: CGSize {
    return CGSize(width: contentWidth, height: contentHeight)
}

override func prepare() {
    // 1
    //You only calculate the layout attributes if cache is empty and the collection view exists.
    /*guard cache.isEmpty == true, let collectionView = collectionView else {
        return
    }*/
    cache.removeAll()
    guard cache.isEmpty == true || cache.isEmpty == false, let collectionView = collectionView else {
        return
    }
    // 2
    //This declares and fills the xOffset array with the x-coordinate for every column based on the column widths. The yOffset array tracks the y-position for every column.
    let columnWidth = contentWidth / CGFloat(numberOfColumns)
    var xOffset = [CGFloat]()
    for column in 0 ..< numberOfColumns {
        xOffset.append(CGFloat(column) * columnWidth)
    }
    var column = 0
    var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)

    // 3
    //This loops through all the items in the first section, as this particular layout has only one section.
    for item in 0 ..< collectionView.numberOfItems(inSection: 0) {

        if collectionView.numberOfItems(inSection: 0) < 3
        {
            collectionView.isScrollEnabled = false
        } else {
            collectionView.isScrollEnabled = true
        }

        let indexPath = IndexPath(item: item, section: 0)

        // 4
        //This is where you perform the frame calculation. width is the previously calculated cellWidth, with the padding between cells removed.

        let photoHeight = delegate.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath)
        let height = cellPadding * 2 + photoHeight
        let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
        let insetFrame = frame.insetBy(dx: 7, dy: 4)

        collectionView.contentInset = UIEdgeInsets.init(top: 15, left: 12, bottom: 0, right: 12)

        // 5
        //This creates an instance of UICollectionViewLayoutAttribute, sets its frame using insetFrame and appends the attributes to cache.
        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        attributes.frame = insetFrame
        cache.append(attributes)

        // 6
        //This expands contentHeight to account for the frame of the newly calculated item.
        contentHeight = max(contentHeight, frame.maxY)
        yOffset[column] = yOffset[column] + height

        column = column < (numberOfColumns - 1) ? (column + 1) : 0
    }
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{

    var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()

    // Loop through the cache and look for items in the rect
    for attributes in cache {
        if attributes.frame.intersects(rect) {
            visibleLayoutAttributes.append(attributes)
        }
    }
    return visibleLayoutAttributes
}

仅供参考:在 MainStoryboard 中,我禁用了“Adjust Scroll View Insets”,正如许多其他主题和论坛所建议的那样......

【问题讨论】:

    标签: ios swift xcode swift3 uicollectionview


    【解决方案1】:

    我猜你已经找到了答案,但是自从我遇到这个问题后,我就在这里为下一个人发帖。

    这里的诀窍是 contentHeight 实际上永远不会变小。

    contentHeight = max(contentHeight, frame.maxY)
    

    这是一个非减函数。

    若要修复它,只需在调用 prepare 时将 contentHeight 设置为 0:

    guard cache.isEmpty == true || cache.isEmpty == false, let 
      collectionView = collectionView else {
        return
    }
    contentHeight = 0
    

    【讨论】:

    • 这实际上是正确的,我已经找到了答案,但这就是我想出的答案。忘记发布我的答案了,谢谢!
    • 完美运行!谢谢
    猜你喜欢
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 2021-06-19
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多