滚动时,CollectionView中的复选框正在更改位置

时间:2018-08-29 09:58:09

标签: ios swift uicollectionviewcell

我有collectionView(3 * 3),其中包含我要从服务器加载的图像,并且在每个单元格的左上角放置了一个复选框,以便我可以选择这些单元格,并根据选定的单元格获取ID各个单元格的图像(来自服务器的ID),并且我能够正确执行所有操作。但是,问题是是否有20张图像,并且如果我检查第一次加载的5个随机单元格,并且当我向下滚动以选择其他单元格时,已经检查了5个其他随机复选框,并且如果我再次向上滚动其他一些检查5个随机单元。似乎由于UICollectionView DataSource方法的cellForItemAtIndexPath中的出队列可重用属性,选中的复选框正在更改位置。

我不知道如何克服这个问题。如果有人知道该怎么做,请帮助我。我将在到目前为止编写的代码和一些模拟器屏幕截图的下方发布,以更好地理解问题...

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)
    } 
}

3 个答案:

答案 0 :(得分:2)

CollectionView出队是您的单元格。要消除这一点,您需要维护一组选定的证书。请按照以下步骤操作。

  1. 创建一个数组arrSelectedIndex : [Int] = []

  2. cellForRow中,

    • 首先检查arrSelectedIndex中可用的当前索引吗?如果是,则将您的单元格设置为选中状态,否则不要选中它。

    • 像下面的buttonCheck.tag = indexPath.item

    • 一样将标记添加到您的选中按钮
  3. 如果要在选中按钮操作中选择图像,请执行以下操作。

    • 获取按钮标签,让aTag = sender.tag
    • 现在检查该索引是否在arrSelectedIndex中可用吗?如果是,则从arrSelectedIndex中删除该索引,否则追加该数组。
    • 立即刷新您的手机。
  4. 如果要在didSelectItem即时检查按钮操作中选择图像,请执行以下操作。

    • 现在检查此选定的索引(indexPath.item)是否在arrSelectedIndex中可用吗?如果是,则从arrSelectedIndex中删除该索引,否则追加该数组。
    • 立即刷新您的手机。

由于此过程很漫长,因此我只能向您解释如何执行此操作。如果需要进一步的帮助,您可以询问。

答案 1 :(得分:1)

这是预期的。因为您正在重用单元格。

考虑一下。您选择前2个单元格,然后向下滚动。您的此功能将称为func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {。现在,这可能会从您选择的前两个单元格中获取视图,并且它们的复选框也已被选中。

您需要取消设置它们,并根据它们的最后状态对其进行设置。

我建议向您的isCertificateSelected模型添加另一个属性Certificate。每次用户点击一个单元格时,您都会检索模型,并设置/取消设置此bool。调用collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)时,您再次检索isCertificateSelected,并相应地设置了复选框。

答案 2 :(得分:1)

创建一个数组var Status1CheckList = [Int]()

然后在cellForItemAt indexPath中检查类似情况

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)

和清单方法,选择按钮后重新加载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()
}