UICollectionView exception in UICollectionViewLayoutAttributes from iOS7

后端 未结 7 872
离开以前
离开以前 2020-12-07 15:55

I have done a View in CollectionView with CustomLayout. In iOS6 it worked great but iOS7 it throws an exception like this.

Terminating app due to uncaught exception

7条回答
  •  时光取名叫无心
    2020-12-07 16:43

    I'm not entirely certain how or why, but this appears to be fixed in iOS 12, supporting both supplementary view resizing and prefetching. The trick for me was to make sure things are happening in the correct order.

    Here is a working implementation of a stretchable header view. Notice the implementation of the header resizing happening in layoutAttributesForElements(in rect: CGRect):

    class StretchyHeaderLayout: UICollectionViewFlowLayout {
    
        var cache = [UICollectionViewLayoutAttributes]()
    
        override func prepare() {
            super.prepare()
    
            cache.removeAll()
    
            guard let collectionView = collectionView else { return }
    
            let sections = [Int](0.. Bool {
            return true
        }
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    
            let visibleAttributes = cache.filter { rect.contains($0.frame) || rect.intersects($0.frame) }
    
            guard let collectionView = collectionView else { return visibleAttributes }
    
            // Find the header and stretch it while scrolling.
            guard let header = visibleAttributes.filter({ $0.representedElementKind == StretchyCollectionHeaderKind }).first else { return visibleAttributes }
            header.frame.origin.y = collectionView.contentOffset.y
            header.frame.size.height = headerHeight.home - collectionView.contentOffset.y
            header.frame.size.width = collectionView.frame.size.width
    
            return visibleAttributes
        }
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
            let attributes = super.layoutAttributesForItem(at: indexPath as IndexPath)?.copy() as! UICollectionViewLayoutAttributes
            guard collectionView != nil else { return attributes }
    
            attributes.frame.origin.y =  headerHeight.home + attributes.frame.origin.y
    
            return attributes
        }
    
        override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
            return UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: StretchyCollectionHeaderKind, with: indexPath)
        }
    
        override var collectionViewContentSize: CGSize {
            get {
                guard let collectionView = collectionView else { return .zero }
    
                let numberOfSections = collectionView.numberOfSections
                let lastSection = numberOfSections - 1
                let numberOfItems = collectionView.numberOfItems(inSection: lastSection)
                let lastItem = numberOfItems - 1
    
                guard let lastCell = layoutAttributesForItem(at: IndexPath(item: lastItem, section: lastSection)) else { return .zero }
    
                return CGSize(width: collectionView.frame.width, height: lastCell.frame.maxY + sectionInset.bottom)
            }
        }
    }
    

    P.S.: I'm aware the cache doesn't actually serve any purpose at this point :)

提交回复
热议问题