自定义 UICollectionViewFlowLayout 不起作用

埃德尔

我正在尝试做一个类似于 Apple News 应用程序自定义 Flow LayoutflowLayout.delegate = self是在viewDidLoad()方法,而我的网络代码是在一个async的方法viewDidAppear()问题是自定义流布局的方法在我可以从服务器检索所有数据之前被调用,因此应用程序崩溃。关于如何使其工作的任何想法?这是我的ViewController实现:

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, AppleNewsFlowLayoutDelegate {

    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var flowLayout: AppleNewsFlowLayout!

    var newsArray = [News]()
    var getFromDb = GetFromDb()

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        if getFromDb.news.isEmpty {
            loadStore()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.dataSource = self
        collectionView.delegate = self
        flowLayout.delegate = self
    }

    func loadStore() {
        let urlString = "https://url"
        self.getFromDb.getBreaksFromDb(url: urlString) { (breaksDataCell) in
            if !breaksDataCell.isEmpty {
                DispatchQueue.main.async(execute: {
                    self.collectionView.reloadData()
                })
            }
        }
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return getFromDb.news.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // Filling the cells with the correct info...
        return cell
    }

func AppleNewsFlowLayout(_ AppleNewsFlowLayout: AppleNewsFlowLayout, cellTypeForItemAt indexPath: IndexPath) -> NewsCellType {
    return getFromDb.news[indexPath.row].cellType
}

}

下面是新闻的结构:

struct News {
let image: String
let provider: String
let title: String
let cellType: NewsCellType

init(image: String, provider: String, title: String, cellType: NewsCellType) {
    self.image = image
    self.provider = provider
    self.title = title
    self.cellType = cellType
}}

流布局类

protocol AppleNewsFlowLayoutDelegate: class {
    func AppleNewsFlowLayout(_ AppleNewsFlowLayout: AppleNewsFlowLayout, cellTypeForItemAt indexPath: IndexPath) -> NewsCellType
}

class AppleNewsFlowLayout: UICollectionViewFlowLayout {

    var maxY: CGFloat = 0.0
    var isVSetOnce = false
    weak var delegate: AppleNewsFlowLayoutDelegate?
    var attributesArray: [UICollectionViewLayoutAttributes]?

    private var numberOfItems:Int{
        return (collectionView?.numberOfItems(inSection: 0))!
    }

    override func prepare() {
        for item in 0 ..< numberOfItems{
            super.prepare()
            minimumLineSpacing = 10
            minimumInteritemSpacing = 16
            sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: 10, right: 16)
        }
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        guard let newsType: NewsCellType = delegate?.AppleNewsFlowLayout(self, cellTypeForItemAt: indexPath) else {
            fatalError("AppleNewsFlowLayoutDelegate method is required.")
        }

        let screenWidth = UIScreen.main.bounds.width
        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        var x = sectionInset.left
        maxY = maxY + minimumLineSpacing

        switch newsType {

        case .big:
            let width = screenWidth - sectionInset.left - sectionInset.right
            attributes.frame = CGRect(x: x, y: maxY, width: width, height: width * 1.2)
            maxY += width * 1.2

        case .horizontal:
            let width = screenWidth - sectionInset.left - sectionInset.right
            attributes.frame = CGRect(x: x, y: maxY, width: width, height: 150)
            maxY += 150

        case .vertical:
            let width = (screenWidth - minimumInteritemSpacing - sectionInset.left - sectionInset.right) / 2
            x = isVSetOnce ? x + width + minimumInteritemSpacing : x
            maxY = isVSetOnce ? maxY-10 : maxY
            attributes.frame = CGRect(x: x, y: maxY, width: width, height: screenWidth * 0.8)
            if isVSetOnce {
                maxY += screenWidth * 0.8
            }
            isVSetOnce = !isVSetOnce
        }
        return attributes
    }


    override var collectionViewContentSize: CGSize {
        return CGSize(width: UIScreen.main.bounds.width, height: maxY)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        if attributesArray == nil {
            attributesArray = [UICollectionViewLayoutAttributes]()
            print(collectionView!.numberOfItems(inSection: 0) - 1)
            for i in 0 ... collectionView!.numberOfItems(inSection: 0) - 1
            {
                let attributes = self.layoutAttributesForItem(at: IndexPath(item: i, section: 0))
                attributesArray!.append(attributes!)
            }
        }
        return attributesArray
    }
}
库马尔·雷迪

当我们处理自定义集合视图流布局时,您需要做两件事。

自定义流布局中 prepare() 方法的变化只有当项目数大于 0 时,您才会开始准备布局。

private var numberOfItems:Int{
    return (collectionView?.numberOfItems(inSection: 0))!
}

override func prepare() {
        for item in 0 ..< numberOfItems{ }
}

每当您想对 customFlowLayout 中的 collectionView 项目执行某些操作时,请使用numberOfItems属性以避免崩溃。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章