簡體   English   中英

UICollectionView:組合布局禁用預取?

[英]UICollectionView: compositional layout disables prefetching?

我有一個非常簡單的UICollectionView ,它使用組合布局輕松實現動態單元高度。 不幸的是,這樣做似乎會禁用使用UICollectionViewDataSourcePrefetching的內容預取。 在以下示例代碼中, collectionView(_:prefetchItemsAt:)方法僅在集合視圖初始顯示時調用一次。 沒有滾動動作會導致對該方法的進一步調用。

我該怎么做才能使預取工作?

class ViewController: UIViewController, 
    UICollectionViewDataSource,
    UICollectionViewDelegate,
    UICollectionViewDataSourcePrefetching
{
    @IBOutlet var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.collectionViewLayout = createLayout()
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.prefetchDataSource = self
        collectionView.register(MyCell.self, forCellWithReuseIdentifier: "cell")
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
        cell.label.text = String(repeating: "\(indexPath) ", count: indexPath.item)

        return cell
    }

    // this is only called once. Why?
    func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
        print("prefetch for \(indexPaths)")
    }

    private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { (_, _) -> NSCollectionLayoutSection? in

            let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                              heightDimension: .estimated(44))
            let item = NSCollectionLayoutItem(layoutSize: size)

            let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)
            group.interItemSpacing = .fixed(16)

            let section = NSCollectionLayoutSection(group: group)
            section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)
            section.interGroupSpacing = 8

            return section
        }

        return layout
    }
}

class MyCell: UICollectionViewCell {
    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        backgroundColor = .orange
        contentView.addSubview(label)

        label.translatesAutoresizingMaskIntoConstraints = false
        label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
        label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

(使用 Xcode 11.5 / iOS collectionView出口連接到故事板中的全屏實例)

編輯:進一步的測試表明heightDimension: .estimated(44)似乎是原因。 將其替換為.absolute(44)可以再次進行預取,但這當然違背了使用多行文本進行這種布局的目的。 似乎是一個錯誤,如果有人想欺騙它,我已經提交了 FB7849272。

編輯/2:暫時,我可以通過使用普通的舊流布局並計算每個單獨的單元格高度來避免這種情況,這也使預取再次工作。 盡管如此,我很好奇在仍然使用組合布局的同時是否沒有解決方法,所以我添加了一個賞金。

是的..!! 沒有辦法對動態大小的單元格使用預取,您必須為其使用collectionView willDisplay forItemAt

我剛剛收到來自 Apple 的反饋,要求我在 Xcode 13.1 中重新測試這個問題,你瞧,這個錯誤確實已經修復了。

我和你有同樣的問題,但我設法解決了。 我的布局的尺寸是用分數計算的,而不是估計的:

layoutSize: NSCollectionLayoutSize(
          widthDimension: .fractionalWidth(1.0),
          heightDimension: .fractionalWidth(2/3)))

並且,在委托方法 prefetchItemsAt 中,您可以使用 indexPaths 來計算您需要在服務器上請求的偏移量。 例如:

var model : [YourModel] = []
collectionView.dataSource = self
collectionView.prefetchDataSource = self

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

func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
        self.loadMore(for: indexPaths)
    }

func loadMore(for indexPaths: [IndexPath]) {
       for index in indexPaths where index.row >= (self.model.count - 1) {
           manager?.requestCharacters(withOffset: model.count, onSuccess: { [unowned self] (objects) in
                    self.model += objects
                    self.collectionView.reloadData()
                }, onError: { (error) in
                    print(error.localizedDescription)
                })
                return
            }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM