前言
使用 collectionView 一屏只展示一个 cell ,一次只加载当前 cell,还要能够缓存已加载过的 cell ,使 cell 不重复加载,听着好像就是将 collectionView 的复用机制禁用掉。用collectionView 实现这个需求,就出现了两个冲突点,一个是collectionView 会预加载后面的 cell ,另一个是会释放掉没在屏幕中显示的 cell 。
示例:
思路
- 将加载过的视图用一个字典存起来
- 当 cell 从重用池中取出来后,将字典中存放的对应视图 加载到 cell 上展示
- 当从字典中没有取到对应的视图时,就去创建新视图
主要实现代码
缓存的字典
var validViewDict:[Int:CommentView] = [:]
加载 cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.contentView.subviews.forEach { $0.removeFromSuperview()}
if let validView = validViewDict[indexPath.item] {
validView.frame = cell.contentView.bounds
cell.contentView.addSubview(validView)
}
return cell
}
创建视图时机
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard scrollView.isTracking || scrollView.isDragging else {
return
}
let percent = scrollView.contentOffset.x/scrollView.bounds.size.width
let maxCount = Int(round(scrollView.contentSize.width/scrollView.bounds.size.width))
var leftIndex = Int(floor(Double(percent)))
leftIndex = max(0, min(maxCount - 1, leftIndex))
let rightIndex = leftIndex + 1;
if percent < 0 || rightIndex >= maxCount {
return
}
let remainderRatio = percent - CGFloat(leftIndex)
if rightIndex == currentIndex {
//当前选中的在右边,用户正在从右边往左边滑动
if validViewDict[leftIndex] == nil && remainderRatio < (1 - initListPercent) {
initListIfNeeded(at: leftIndex)
}
}else {
//当前选中的在左边,用户正在从左边往右边滑动
if validViewDict[rightIndex] == nil && remainderRatio > initListPercent {
initListIfNeeded(at: rightIndex)
currentIndex = rightIndex
}
}
}
创建视图并存入字典
func initListIfNeeded(at index: Int) {
var existedView = validViewDict[index]
if existedView != nil {
//列表已经创建好了
return
}
existedView = initValidView(initViewAt: index)
guard let commentView = existedView else {
return
}
validViewDict[index] = commentView
let cell = collectView.cellForItem(at: IndexPath(item: index, section: 0))
cell?.contentView.subviews.forEach { $0.removeFromSuperview() }
commentView.frame = cell?.contentView.bounds ?? CGRect.zero
cell?.contentView.addSubview(commentView)
}
结语
使用字典保存加载的视图,每次加载 cell 时先移除子视图,再加载字典中的视图,避免了复用带来的界面展示内容不对的问题。在滚动代理 scrollViewDidScroll 中计算创建视图的时机,保证只创建当前展示的cell 的视图。这样我们就巧妙的实现了“如何让cell 不重复创建并且只在展示的时候才创建”。
感谢您的阅读和参与,HH思无邪愿与您一起在技术的道路上不断探索。如果您喜欢这篇文章,不妨留下您宝贵的赞!如果您对文章有任何疑问或建议,欢迎在评论区留言,我会第一时间处理,您的支持是我前行的动力,愿我们都能成为更好的自己!