I have an issue in my UICollectionView where some cells seem to be neither part of the indexPathForVisibleItems
, nor are they taken from the caching queue with dequeueReusableCell
. The result is, that some cells don't receive required updates of data during a scroll and show old behavior.
For simplicity, I reduced the project to the neccessary Controllers and a minimized Storyboard. Basically, I've got a NavigationController as EntryPoint that contains the MainViewController, which itself contains a ContainerView with the CollectionViewController.
The NavigationController uses the default edit button to switch between edit and non-edit mode - this should result in an image displayed on the cells while in edit mode. Therefore I implemented setEditing
and changed the images hidden property of all visible cells, and additionally i set the images hidden property while dequeuing - assuming that cells are either visible or they will be dequeued in the future.
This works fine while the CollectionView is scrolled from top to bottom. But when I switch back from Edit-Mode to Non-Edit-Mode while scrolled to the bottom and then scroll back to the top, some cells still display the image (more specific: at least the same row, which is the first non-visible row). Somehow I'd assume that the dequeued cells and the visible cells would be complementary parts of the displayed data, which should result in either the images being hidden/unhidden during the setEditing
call (which works for the first 4 rows of cells) or being hidden/unhidden during the dequeuing (which works for the last few rows, except the third row in my example)
Code for the CollectionViewController:
import Foundation
import UIKit
import Photos
class CollectionViewController : UICollectionViewController {
fileprivate let CELL_ID = "PicCell"
fileprivate let IMAGE_VIEW_SIZE = 104
var selectedIndex = -1
var itemCount = 28
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
print(self.isEditing)
collectionView?.allowsMultipleSelection = editing
for indexPath in (collectionView?.indexPathsForSelectedItems)! {
collectionView?.deselectItem(at: indexPath, animated: true)
}
for indexPath in (collectionView?.indexPathsForVisibleItems)! {
let cell = collectionView?.cellForItem(at: indexPath) as? PicCell
if cell != nil {
cell?.editing = editing
}
}
}
override func viewDidLoad() {
self.navigationItem.rightBarButtonItem = self.editButtonItem
collectionView?.reloadData()
}
}
extension CollectionViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemCount;
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print(indexPath.row)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CELL_ID, for: indexPath) as! PicCell
cell.editing = isEditing
cell.isSelected = false
return cell;
}
}
Code for PicCell
import Foundation
import UIKit
class PicCell : UICollectionViewCell {
@IBOutlet weak var deleteBtn: UIImageView!
var editing:Bool = false{
didSet {
self.deleteBtn.isHidden = !editing
self.deleteBtn.tintColor = UIColor.blue
}
}
override var isSelected: Bool{
didSet {
if isSelected && editing {
self.deleteBtn.tintColor = UIColor.red
} else {
self.deleteBtn.tintColor = UIColor.blue
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
self.editing = false
self.isSelected = false
}
}
Code for MainViewController
import Foundation
import UIKit
class MainViewController: UIViewController {
override func viewDidLoad() {
self.navigationItem.rightBarButtonItem = self.editButtonItem
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
collectionController?.setEditing(editing, animated: animated)
}
var collectionController : CollectionViewController? = nil
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowCollectionView" {
collectionController = segue.destination as! CollectionViewController
}
}
}
as you can see I'm using constant values for the item count in a single section, which shouldn't be a big deal.
I don't know if it matters, but my cells are 104px in width and height, the image is rendered as template and the UIContainerView is 343 in width and 473 in height, i'm testing on an iPhone 7+ simulator with iOS 10.1
If there's anything missing from the storyboard, i might add some screenshots, but i'm unsure what to post exactly
Thanks in advance for your help and kind regards
Christian
Edit: just to be clear with my question: I'm looking for some advice for either obvious mistakes in my code or a way to access UICollectionViewCells that are neither in the list of visible items nor dequeued during scroll - there might be a way to access those cells i simplay don't know about
You can change this behavior if you turn off prefetching:
collectionView?.isPrefetchingEnabled = false
Or you can keep it on, but then either:
hook into UICollectionViewDelegate
methods didEndDisplaying
and willDisplay
to know as cells appear and disappear independent of cellForItemAt
; or
have cells do some KVO on some view controller property or observe some notification that the view controller will initiate in order to know whether to change their state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With