本页面的内容来自于网友的分享,您也可以点击此处创建您自己的内容。 注意:本页面将在之后被自动销毁。

class MakeFriendViewControllerLayout: UICollectionViewLayout {

    var feeds: [MakeFriendFeeds]?

    var hasHeader = false

    var verticalGap: Double = 30.0

    

    private var headerHeight = 0.0

    private var layoutAttrs = [UICollectionViewLayoutAttributes]()

    private var headerAttrs = [UICollectionViewLayoutAttributes]()

    

    // TODO: 性能优化,保存当前index之前的结果,以便从上一次的计算结果处开始遍历,来减少遍历次数

    private func notCommFeedsNum(index: Int) -> Int {

        guard let feeds = feeds, index < feeds.count else {

            return 0

        }


        var num = 0

        for (i, feed) in feeds.enumerated() {

            if i >= index {

                break

            }

            if feed.type != .commonFeed {

                num += 1

            }

        }

        return num

    }

    

    override func invalidateLayout() {

//        headerHeight = 0

        headerAttrs.removeAll()

        layoutAttrs.removeAll()

        super.invalidateLayout()

    }

    

    override func prepare() {

        super.prepare()

        guard let feeds = feeds, let collectionView = collectionView else { return }

        let section = [Int](0..<collectionView.numberOfSections)

        headerHeight = 0

        for i in section {

            if let headerAttr = layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: i)) {

                if !headerAttr.frame.isEmpty {

                    headerHeight = headerAttr.frame.height

                    headerAttrs.append(headerAttr)

                }

            }

        }

        let num = feeds.count

        for i in 0..<num {

            if let attr = layoutAttributesForItem(at: IndexPath.init(item: i, section: 0)) {

                layoutAttrs.append(attr)

            }

        }

    }

    

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {

        return true

    }

    

    override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

        guard let collectionView = collectionView else { return nil }

        let attr = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)

        let y = collectionView.contentOffset.y < 0 ? 0 : collectionView.contentOffset.y

        var size = CGSize.zero

        if let delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout {

            size = delegate.collectionView!(collectionView, layout: self, referenceSizeForHeaderInSection: indexPath.section)

        }

        if size.width.isZero || size.height.isZero {

            attr.zIndex = 0

        } else {

            attr.zIndex = 1024

        }

        attr.frame = CGRect(origin: CGPoint(x: 0, y: y), size: size)

        return attr

    }

    

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

        let currentLayout = UICollectionViewLayoutAttributes(forCellWith: indexPath)

        var origin = CGPoint(x: 0, y: headerHeight)

        var currFrame = currentLayout.frame

        if let collectionView = self.collectionView, let layoutDelegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout {

            currFrame.size = layoutDelegate.collectionView?(collectionView, layout: self, sizeForItemAt: indexPath) ?? CGSize.zero

        }

        currFrame.origin = origin

        currentLayout.frame = currFrame

        

        var lastLayout: UICollectionViewLayoutAttributes?

        if indexPath.row > 0 {

            lastLayout = layoutAttrs[indexPath.row-1]

        }

        guard let lastLayout = lastLayout, let currFeeds = feeds?[safe: indexPath.row] else {

            return currentLayout

        }

        

        origin.y = lastLayout.frame.maxY + spacingAt(index: indexPath.row)

        if currFeeds.type == .commonFeed {

            if (indexPath.row - notCommFeedsNum(index: indexPath.row)) % 2 == 0 {

                origin.x = 0

            } else {

                origin.x = lastLayout.frame.maxX + 8

                origin.y = lastLayout.frame.origin.y

            }

        }

        currFrame.origin = origin

        currentLayout.frame = currFrame

        return currentLayout

    }

    

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        var res = [UICollectionViewLayoutAttributes]()

        res.append(contentsOf: headerAttrs)

//        res.append(contentsOf: layoutAttrs.filter { rect.intersects($0.frame) })

        return res

    }

    

    override var collectionViewContentSize: CGSize {

        guard let collectionView = collectionView else {

            return CGSize.zero

        }

        let h = layoutAttrs.last?.frame.maxY ?? 0

        return CGSize(width: collectionView.width, height: h)

    }

    

    private func spacingAt(index: Int) -> Double {

        guard let feeds = feeds, index < feeds.count - 1 else {

            return 8.0

        }

        let currFeeds = feeds[index]

        let lastFeeds = feeds[index-1]

        if lastFeeds.type == .titleText {

            return 0

        }

        if (lastFeeds.type == .porcelain && currFeeds.type != .porcelain) || (currFeeds.type == .porcelain && lastFeeds.type != .porcelain) {

            return verticalGap

        }

        if lastFeeds.type != currFeeds.type && lastFeeds.type != .card && currFeeds.type != .card {

            return verticalGap

        }

        

        switch currFeeds.type {

        case .hotParty, .partyRoom, .voice, .datingRoom:

            return verticalGap

        case .titleText:

            return 0.0

        case .commonFeed:

            if (index - notCommFeedsNum(index: index)) % 2 == 0 {

                return 8.0

            } else {

                return 0.0

            }

        default:

            return 8.0

        }

    }

}