首页 文章

如何使集合视图颠倒?

提问于
浏览
-2

我正在使用具有垂直滚动方向的Collection视图作为我的应用程序 . 在这里,我想让我的Collection视图在不使用任何CGAffine Transform的情况下颠倒显示 . 在Flow Layout的帮助下有可能吗?

我喜欢使用集合视图来实现聊天

提前致谢

1 回答

  • 1
    class ChatCollectionViewFlowLayout: UICollectionViewFlowLayout {
    
        private var topMostVisibleItem    =  Int.max
        private var bottomMostVisibleItem = -Int.max
    
        private var offset: CGFloat = 0.0
        private var visibleAttributes: [UICollectionViewLayoutAttributes]?
    
        private var isInsertingItemsToTop    = false
        private var isInsertingItemsToBottom = false
    
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
            // Reset each time all values to recalculate them
            // ════════════════════════════════════════════════════════════
    
            // Get layout attributes of all items
            visibleAttributes = super.layoutAttributesForElements(in: rect)
    
            // Erase offset
            offset = 0.0
    
            // Reset inserting flags
            isInsertingItemsToTop    = false
            isInsertingItemsToBottom = false
    
            return visibleAttributes
        }
    
        override func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) {
    
            // Check where new items get inserted
            // ════════════════════════════════════════════════════════════
    
            // Get collection view and layout attributes as non-optional object
            guard let collectionView = self.collectionView       else { return }
            guard let visibleAttributes = self.visibleAttributes else { return }
    
    
            // Find top and bottom most visible item
            // ────────────────────────────────────────────────────────────
    
            bottomMostVisibleItem = -Int.max
            topMostVisibleItem    =  Int.max
    
            let container = CGRect(x: collectionView.contentOffset.x,
                                   y: collectionView.contentOffset.y,
                                   width:  collectionView.frame.size.width,
                                   height: (collectionView.frame.size.height - (collectionView.contentInset.top + collectionView.contentInset.bottom)))
    
            for attributes in visibleAttributes {
    
                // Check if cell frame is inside container frame
                if attributes.frame.intersects(container) {
                    let item = attributes.indexPath.item
                    if item < topMostVisibleItem    { topMostVisibleItem    = item }
                    if item > bottomMostVisibleItem { bottomMostVisibleItem = item }
                }
            }
    
    
            // Call super after first calculations
            super.prepare(forCollectionViewUpdates: updateItems)
    
    
            // Calculate offset of inserting items
            // ────────────────────────────────────────────────────────────
    
            var willInsertItemsToTop    = false
            var willInsertItemsToBottom = false
    
            // Iterate over all new items and add their height if they go inserted
            for updateItem in updateItems {
                switch updateItem.updateAction {
                case .insert:
                    if topMostVisibleItem + updateItems.count > updateItem.indexPathAfterUpdate!.item {
                        if let newAttributes = self.layoutAttributesForItem(at: updateItem.indexPathAfterUpdate!) {
    
                            offset += (newAttributes.size.height + self.minimumLineSpacing)
                            willInsertItemsToTop = true
                        }
    
                    } else if bottomMostVisibleItem <= updateItem.indexPathAfterUpdate!.item {
                        if let newAttributes = self.layoutAttributesForItem(at: updateItem.indexPathAfterUpdate!) {
    
                            offset += (newAttributes.size.height + self.minimumLineSpacing)
                            willInsertItemsToBottom = true
                        }
                    }
    
                case.delete:
                    // TODO: Handle removal of items
                    break
    
                default:
                    break
                }
            }
    
    
            // Pass on information if items need more than one screen
            // ────────────────────────────────────────────────────────────
    
            // Just continue if one flag is set
            if willInsertItemsToTop || willInsertItemsToBottom {
    
                // Get heights without top and bottom
                let collectionViewContentHeight = collectionView.contentSize.height
                let collectionViewFrameHeight   = collectionView.frame.size.height - (collectionView.contentInset.top + collectionView.contentInset.bottom)
    
                // Continue only if the new content is higher then the frame
                // If it is not the case the collection view can display all cells on one screen
                if collectionViewContentHeight + offset > collectionViewFrameHeight {
    
                    if willInsertItemsToTop {
                        CATransaction.begin()
                        CATransaction.setDisableActions(true)
                        isInsertingItemsToTop = true
    
                    } else if willInsertItemsToBottom {
                        isInsertingItemsToBottom = true
                    }
                }
            }
        }
    
        override func finalizeCollectionViewUpdates() {
    
            // Set final content offset with animation or not
            // ════════════════════════════════════════════════════════════
    
            // Get collection view as non-optional object
            guard let collectionView = self.collectionView else { return }
    
            if isInsertingItemsToTop {
    
                // Calculate new content offset
                let newContentOffset = CGPoint(x: collectionView.contentOffset.x,
                                               y: collectionView.contentOffset.y + offset)
    
                // Set new content offset without animation
                collectionView.contentOffset = newContentOffset
    
                // Commit/end transaction
                CATransaction.commit()
    
            } else if isInsertingItemsToBottom {
    
                // Calculate new content offset
                // Always scroll to bottom
                let newContentOffset = CGPoint(x: collectionView.contentOffset.x,
                                               y: collectionView.contentSize.height + offset - collectionView.frame.size.height + collectionView.contentInset.bottom)
    
                // Set new content offset with animation
                collectionView.setContentOffset(newContentOffset, animated: true)
            }
        }
    }
    

    也请检查,它可能设置集合视图作为聊天行为像颠倒https://gist.github.com/jochenschoellig/04ffb26d38ae305fa81aeb711d043068

相关问题