【发布时间】:2020-10-24 20:34:55
【问题描述】:
我有一个非常简单的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 13.5。collectionView 插座连接到故事板中的全屏实例)
编辑:进一步的测试表明heightDimension: .estimated(44) 似乎是原因。用.absolute(44) 替换它会使预取再次工作,但这当然违背了使用多行文本进行这种布局的目的。似乎是一个错误,如果有人想欺骗它,我已经提交了 FB7849272。
EDIT/2:目前,我可以通过使用普通的旧流布局并计算每个单独的单元格高度来避免这种情况,这也使预取再次工作。不过,我很好奇在仍然使用组合布局的同时是否有解决方法,所以我添加了一个赏金。
【问题讨论】:
-
我也有同样的问题...
-
你成功了吗?
-
不,不幸的是,当我上次测试它时,问题仍然存在于 iOS 14 中。
-
这在 iOS 14.5 上仍然是一个问题……
-
在 Xcode 13.1 中修复,见下文。
标签: ios swift uicollectionview prefetch