如何使集合视图颠倒?

时间:2018-05-10 09:37:14

标签: ios swift collectionview uicollectionviewflowlayout

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

我喜欢使用集合视图

来实现聊天

提前致谢

1 个答案:

答案 0 :(得分: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