UICollectionView insert cells above maintaining position (like Messages.app)

后端 未结 20 2102
渐次进展
渐次进展 2020-12-02 07:23

By default Collection View maintains content offset while inserting cells. On the other hand I\'d like to insert cells above the currently displaying ones so that they appea

20条回答
  •  刺人心
    刺人心 (楼主)
    2020-12-02 08:07

    Here's a slightly tweaked version of Peter's solution (subclassing flow layout, no upside-down, lightweight approach). It's Swift 3. Note UIView.animate with zero duration - that's to allow the animation of the even/oddness of the cells (what's on a row) animate, but stop the animation of the viewport offset changing (which would look terrible)

    Usage:

            let layout = self.collectionview.collectionViewLayout as! ContentSizePreservingFlowLayout
            layout.isInsertingCellsToTop = true
            self.collectionview.performBatchUpdates({
                if let deletionIndexPaths = deletionIndexPaths, deletionIndexPaths.count > 0 {
                    self.collectionview.deleteItems(at: deletionIndexPaths.map { return IndexPath.init(item: $0.item+twitterItems, section: 0) })
                }
                if let insertionIndexPaths = insertionIndexPaths, insertionIndexPaths.count > 0 {
                    self.collectionview.insertItems(at: insertionIndexPaths.map { return IndexPath.init(item: $0.item+twitterItems, section: 0) })
                }
            }) { (finished) in
                completionBlock?()
            }
    

    Here's ContentSizePreservingFlowLayout in its entirety:

        class ContentSizePreservingFlowLayout: UICollectionViewFlowLayout {
            var isInsertingCellsToTop: Bool = false {
                didSet {
                    if isInsertingCellsToTop {
                        contentSizeBeforeInsertingToTop = collectionViewContentSize
                    }
                }
            }
            private var contentSizeBeforeInsertingToTop: CGSize?
    
            override func prepare() {
                super.prepare()
                if isInsertingCellsToTop == true {
                    if let collectionView = collectionView, let oldContentSize = contentSizeBeforeInsertingToTop {
                        UIView.animate(withDuration: 0, animations: {
                            let newContentSize = self.collectionViewContentSize
                            let contentOffsetY = collectionView.contentOffset.y + (newContentSize.height - oldContentSize.height)
                            let newOffset = CGPoint(x: collectionView.contentOffset.x, y: contentOffsetY)
                            collectionView.contentOffset = newOffset
                        })
                    }
                    contentSizeBeforeInsertingToTop = nil
                    isInsertingCellsToTop = false
                }
            }
        }
    

提交回复
热议问题