问题
I have collectionView (3*3) with Images I am loading from server and I placed a checkBox in the top left corner of each cell so that I can select the cells and based on the selected cells I will get ids for the respective cells images(ids coming from server) and I am able do everything right. But, the problem is if there is are 20 images and if I check the 5 random cells which are loaded for the first time and when I scroll down to select other cells 5 other random checkBoxes are already checked and if I scroll up again some other 5 random cells are checked. It appears that the checked checkBoxes are changing positions because of the dequeue reusable property in the cellForItemAtIndexPath of UICollectionView DataSource method..
I have no Idea how to overcome this problem. Please help me If any one knows how to do this. I am posting below the code I wrote so far and some simulator screenshots for better understanding of the problem...
EditCertificatesViewController:
import UIKit
import Alamofire
protocol CheckBoxState {
func saveCheckBoxState(cell: EditCertificateCell)
}
class EditCertificatesViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
@IBOutlet weak var certificatesCollectionView: UICollectionView!
var certificatesArray = [Certificates]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Delete Certificates"
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return certificatesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "editCertificate", for: indexPath) as! EditCertificateCell
if let certificateURL = URL(string: certificatesArray[indexPath.item].imagePath) {
cell.certificateImage.af_setImage(withURL: certificateURL)
}
cell.certificateId.text = "\(certificatesArray[indexPath.item].imageId)"
cell.selectCertificate.customBox()
if selectedCellIndex.contains(indexPath.item) {
cell.selectCertificate.on = true
}
else {
cell.selectCertificate.on = false
}
cell.selectCertificate.tag = indexPath.item
cell.checkState = self
return cell
}
}
extension EditCertificatesViewController: CheckBoxState {
func saveCheckBoxState(cell: EditCertificateCell) {
if cell.selectCertificate.on == true {
cell.selectCertificate.on = false
}
else {
cell.selectCertificate.on = true
}
if selectedCellIndex.contains(cell.selectCertificate.tag) {
selectedCellIndex = selectedCellIndex.filter{$0 != cell.selectCertificate.tag}
}
else {
selectedCellIndex.append(cell.selectCertificate.tag)
}
print("Status1 \(selectedCellIndex.sorted { $0 < $1 })")
// certificatesCollectionView.reloadData()
}
}
EditCertificateCell:
import UIKit
class EditCertificateCell: UICollectionViewCell {
@IBOutlet weak var certificateImage: UIImageView!
@IBOutlet weak var selectCertificate: BEMCheckBox!
@IBOutlet weak var certificateId: UILabel!
@IBOutlet weak var selectCertificateBtn: UIButton!
var checkState: CheckBoxState?
override func awakeFromNib() {
super.awakeFromNib()
self.selectCertificateBtn.addTarget(self, action: #selector(btnTapped(_:event:)), for: .touchUpInside)
}
@objc func btnTapped(_ sender: UIButton,event: UIEvent) {
self.checkState?.saveCheckBoxState(cell: self)
}
}
回答1:
CollectionView dequeue's your cell. To rid of this you need to maintain array of selected certificates. Follow below procedure.
Create an array
arrSelectedIndex : [Int] = []In
cellForRow,First check either current index in available in
arrSelectedIndexor not? If yes, then make your cell as selected otherwise keep it uncheck.Give tag to your check button as like this
buttonCheck.tag = indexPath.item
If you wanted to select images on check button action, do below.
- Get the button tag let
aTag = sender.tag - Now check wther this index is available in
arrSelectedIndexor not? If yes then remove that index from from thearrSelectedIndexotherwise append that array. - reload your cell now.
- Get the button tag let
If you wanted to select images on didSelectItem instaead check button action, do below.
- Now check wther this selected index (indexPath.item) is available in
arrSelectedIndexor not? If yes then remove that index from from thearrSelectedIndexotherwise append that array. - reload your cell now.
- Now check wther this selected index (indexPath.item) is available in
As this procedure is lengthy so I can only explain you how to do this. If need further help then you can ask.
回答2:
This is expected. Because you are reusing the cells.
Consider this. You select the first 2 cells, and now scroll down. This function of yours will be called func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {. Now this might get the views from the first 2 cells, that you had selected, and their checkboxes are already selected too.
You need to unset them, and set them, depending upon their last state.
I would recommend adding another property isCertificateSelected to your Certificate model. Each time the user taps on a cell, you retrieve the model, and set/unset this bool. When collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) is called, you retrieve the isCertificateSelected again, and set the checkbox accordingly.
回答3:
Create an array var Status1CheckList = [Int]()
And in cellForItemAt indexPath check the condition like
if Status1CheckList.contains(indexPath.row) {
cellOfCollection.CheckBtn.setImage(UIImage(named: "check"), for: .normal)
} else {
cellOfCollection.CheckBtn.setImage(UIImage(named: "uncheck"), for: .normal)
}
cellOfCollection.CheckBtn.tag = indexPath.row
cellOfCollection.CheckBtn.addTarget(self, action: #selector(self.checkList), for: .touchUpInside)
And checklist method, After selecting button reload the collectionview
@objc func checkList(_ sender: UIButton) {
if Status1CheckList.contains(sender.tag) {
Status1CheckList = Status1CheckList.filter{ $0 != sender.tag}
} else {
Status1CheckList.append(sender.tag)
}
print("Status1 \(Status1CheckList.sorted { $0 < $1 })")
self.collectionviewObj.reloadData()
}
来源:https://stackoverflow.com/questions/52074636/check-boxes-in-collectionview-are-changing-positions-when-scrolling