CollectionView 单元格和进度条 - 滚动后进度条显示在错误的单元格中

CollectionView Cell and Progress Bar - Progress Bar showing in wrong Cell after scrolling

几天来我一直在寻找这个问题的答案,但似乎无法弄清楚。我有一个带有自定义单元格的 Collection 视图。当您双击 Collection 视图中的一个单元格时,它将下载文件或将其删除(如果之前已下载)。

在下载过程中,进度条会显示下载进度,然后在左上角显示一个小图标。删除时会删除图标。

如果您在第一个下载过程中从一个单元格下载并从另一个单元格删除它工作正常,但前提是两个单元格都在 collection 视图中可见。

如果我从一个单元格下载,然后滚动到屏幕外并从与正在下载的单元格不在同一屏幕的单元格中删除,它会像往常一样删除角图像,然后显示单元格的进度条正在下载。

我不知道这是否是我重复使用细胞的错误???它似乎与我更新单元格或 collection 视图的方式没有任何关系,除了滚动之后,它在所有情况下都有效。

以下是下载或删除文件的2个函数:

func downloadDataToDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath){

    let downloadedAudio = PFObject(className: "downloadedAudio")
    // save all files with unique name / object id
    let selectedObjectId = self.partArray[selectedIndexPath.item].id
    let selectedPartName = self.partArray[selectedIndexPath.item].name

    let query = PFQuery(className: "Part")
    query.whereKey("objectId", equalTo: selectedObjectId)
    query.getFirstObjectInBackground { (object, error) in

        if error != nil || object == nil {
            print("No object for the index selected.")
        } else {
            //print("there is an object, getting the file.")
            downloadedAudio.add(object?.object(forKey: "partAudio") as! PFFile, forKey: selectedPartName)
            let downloadedFile = object?.object(forKey: "partAudio") as! PFFile

            // get the data first so we can track progress
            downloadedFile.getDataInBackground({ (success, error) in
                if (success != nil) {
                    // pin the audio if there is data
                    downloadedAudio.pinInBackground(block: { (success, error) in
                        if success {

                            // reload the cell
                            self.reloadCell(selectedIndexPath: selectedIndexPath, hideProgress: true, hideImage: false, cell: cell)
                            self.inProgress -= 1
                            cell.isUserInteractionEnabled = true

                        }
                    })
                }
            // track the progress of the data
            }, progressBlock: { (percent) in
                self.activityIndicatorView.stopAnimating()
                cell.progessBar.isHidden = false
                //cell.progessBar.transform = cell.progessBar.transform.scaledBy(x: 1, y: 1.1)
                cell.contentView.bringSubview(toFront: cell.progessBar)
                cell.progessBar.setProgress(Float(percent) / Float(100), animated: true)
                cell.isUserInteractionEnabled = false
            })
        }
    }
}

func removeDataFromDevice(cell: JourneyCollectionViewCell, selectedIndexPath: IndexPath, object: PFObject) {

        let selectedPartName = self.partArray[selectedIndexPath.item].name

        // unpin the object from the LocalDataStore
        PFObject.unpinAll(inBackground: [object], block: { (success, error) in
            if success {
                // reduce inProgress
                self.inProgress -= 1
                self.reloadCell(selectedIndexPath: selectedIndexPath, hideProgress: true, hideImage: true, cell: cell)
            }
        })
}

这就是我重新加载单元格的方式

func reloadCell(selectedIndexPath: IndexPath, hideProgress: Bool, hideImage: Bool, cell: JourneyCollectionViewCell) {
    cell.progessBar.isHidden = hideProgress
    cell.imageDownloaded.isHidden = hideImage
    self.collectionView.reloadItems(at: [selectedIndexPath])
}

------------编辑------------

这是我的 cellForItem 功能。目前我正在使用查询来查看本地驱动器并查看文件是否存在,如果存在则添加角图像。这是我第一次在这个地方使用查询,通常它是在登录时查询以填充数组,但这是为了获得比我在这里尝试通过让用户下载和删除文件。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell: JourneyCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! JourneyCollectionViewCell

        cell.imageCell.file = self.partArray[indexPath.item].image
        cell.imageCell.loadInBackground()
        cell.imageCell.layer.masksToBounds = true

    // not sure if its good to run a query here as its constantly updated.
    // query if file is on LDS and add image to indicate
    let cellPartName = self.partArray[indexPath.item].name
    let checkQuery = PFQuery(className: "downloadedAudio")
        checkQuery.whereKeyExists(cellPartName)
        checkQuery.fromLocalDatastore()
        checkQuery.getFirstObjectInBackground(block: { (object, error) in
        if error != nil || object == nil {
            //print("The file does not exist locally on the device, remove the image.")
            cell.imageDownloaded.isHidden = true
            cell.imageDownloaded.image = UIImage(named: "")
            cell.progessBar.isHidden = true

        } else {
            //print("the file already exists on the device, add the image.")
            cell.contentView.bringSubview(toFront: cell.imageDownloaded)
            cell.imageDownloaded.isHidden = false
            cell.imageDownloaded.image = UIImage(named: "download-1")

            }
        })
    return cell
} 

这是 "reuse" 单元的正常功能,用于有效的内存管理目的。您需要做的是重置以下函数中的单元格值:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}

重置是指在您进行任何更新(例如添加左角图标或状态栏)之前,将单元格设置为默认状态。

您需要确保正确维护从中提供 collectionview 数据的数组。例如,如果你有一个数组 A =[1,2,3] 并且你删除了 A[1],那么数组 A 需要是 [1,3].

所以我尝试以编程方式放置进度视图,我尝试在自定义单元格中使用 prepareForReuse class,但都没有直接解决这个问题,但我会继续使用 prepareForReuse,因为我认为它是管理单元格的更简洁的方法比我以前。

似乎起作用的是在 progressBlock 中重新定位单元格

if let downloadingCell = self.collectionView.cellForItem(at: selectedIndexPath) as? JourneyCollectionViewCell {                            downloadingCell.progessBar.isHidden = false
    downloadingCell.contentView.bringSubview(toFront: downloadingCell.progessBar)
    downloadingCell.progessBar.setProgress(Float(percent) / Float(100), animated: true)
    downloadingCell.setNeedsDisplay()
    downloadingCell.isUserInteractionEnabled = false
}