如何使收藏视图倒置?

Posted

技术标签:

【中文标题】如何使收藏视图倒置?【英文标题】:How to make the collection view upside down? 【发布时间】:2018-05-10 09:37:13 【问题描述】:

我正在为我的一个应用程序使用具有垂直滚动方向的 Collection 视图。在这里,我想让我的 Collection 视图在不使用任何 CGAffine 变换的情况下倒置显示。是否可以借助 Flow Layout 的帮助?

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

提前致谢

【问题讨论】:

让我知道为什么它被否决了? 您能描述一下您的目标是什么吗?备注:我不是一个downvoter :) 请说明您进行了哪些研究、您已经尝试过、代码示例等。阅读How to Ask 和minimal reproducible example 并更新您的问题。 【参考方案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

【讨论】:

如果可能的话,您可以发送示例以了解如何使用。

以上是关于如何使收藏视图倒置?的主要内容,如果未能解决你的问题,请参考以下文章

GDAL - 将图像扭曲到倒置的 y 轴坐标系(Apple MapKit)使图像倒置

如果 3d 视图的左右图像倒置,您会看到啥?

如何在 KonvaJS 中的图层上绘制倒置元素

将方向从垂直更改为倒置时更改控制器的颜色

必知必会的设计原则——依赖倒置原则

设备方向倒置不起作用