Check Boxes in CollectionView are changing positions when scrolling

家住魔仙堡 提交于 2019-12-14 03:25:05

问题


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.

  1. Create an array arrSelectedIndex : [Int] = []

  2. In cellForRow,

    • First check either current index in available in arrSelectedIndex or 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

  3. 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 arrSelectedIndex or not? If yes then remove that index from from the arrSelectedIndex otherwise append that array.
    • reload your cell now.
  4. 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 arrSelectedIndex or not? If yes then remove that index from from the arrSelectedIndex otherwise append that array.
    • reload your cell now.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!