【问题标题】:UICollectionView didSelectItemAt() and adding/removing a view based on stateUICollectionView didSelectItemAt() 并根据状态添加/删除视图
【发布时间】:2018-03-25 05:18:56
【问题描述】:

我想为选定的单元格添加复选标记。如果随后取消选择单元格(因此选择了另一个单元格),我想删除复选标记。顶部图像视图独立于集合视图,代表用户相机胶卷中选定的单元格。集合视图的数据源是从 PHAsset 中获取的图像列表。

问题是,如果我不在 indexPath 处重新加载项目,则取消选中的单元格复选标记不会被删除。此外,如果我滚动浏览集合视图,我会看到我什至没有点击的单元格中的随机复选标记。我假设它与细胞的重复使用有关。谁能帮帮我?

下面是视图控制器和单元格中我的代码的 sn-ps...

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoCellReuseIdentifier, for: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
    let requestOptions = PHImageRequestOptions()
    requestOptions.isSynchronous = true
    requestOptions.isNetworkAccessAllowed = true
    requestOptions.deliveryMode = .highQualityFormat

    photoManager.requestImage(for: photoAssets![indexPath.row], targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions, resultHandler: { (image, nil) in
        cell.photoView.image = image
    })

    if cell.isSelected {
        cell.setupCheckmarkBanner()
    }
    else {
        cell.removeCheckmarkBanner()
    }

    if indexPath.row == 0 && self.isFirstLoad {
        self.selectedImageView.image = cell.photoView.image
        collectionView.selectItem(at: indexPath, animated: false, scrollPosition: UICollectionViewScrollPosition.bottom)
        cell.setupCheckmarkBanner()
        self.isFirstLoad = false
    }


    return cell
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    previousIndexPath = indexPath
    collectionView.reloadItems(at: [indexPath])
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if previousIndexPath != indexPath {
        collectionView.reloadItems(at: [indexPath])
        guard let cell = collectionView.cellForItem(at: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
        selectedImageView.image = cell.photoView.image
    }
}


class PhotosCell: UICollectionViewCell {

let photoView = UIImageView()
var checkmarkBannerImageView: UIImageView? 

override init(frame: CGRect) {
    super.init(frame: frame)
    addSubview(photoView)
    photoView.anchor(top: topAnchor, left: leadingAnchor, bottom: bottomAnchor, right: trailingAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

func setupCheckmarkBanner() {
    checkmarkBannerImageView = UIImageView(image: #imageLiteral(resourceName: "check").withRenderingMode(.alwaysTemplate))
    checkmarkBannerImageView?.contentMode = .center
    checkmarkBannerImageView?.contentScaleFactor = 4.0
    checkmarkBannerImageView?.tintColor = .white
    checkmarkBannerImageView?.setBottomBorder(for: .white)
    checkmarkBannerImageView?.convertToCircle(value: 12)

    photoView.addSubview(checkmarkBannerImageView!)
    checkmarkBannerImageView?.anchor(top: photoView.topAnchor, left: nil, bottom: nil, right: photoView.trailingAnchor, paddingTop: 4, paddingLeft: 0, paddingBottom: 0, paddingRight: 4, width: 24, height: 24)
}

func removeCheckmarkBanner() {
    checkmarkBannerImageView?.removeFromSuperview()
    checkmarkBannerImageView?.constraints.forEach{$0.isActive = false }
    checkmarkBannerImageView = nil
}
}

【问题讨论】:

    标签: swift uicollectionview


    【解决方案1】:

    为避免重复使用单元格中出现不需要的内容,您可以覆盖 prepareForReuse() 方法,并在其中完成所有设置工作(例如隐藏复选标记)

    【讨论】:

      【解决方案2】:

      您必须保存所选单元格的索引路径(在 DidSelect 和 DidDescelect 期间创建一个属性并分配,在 cellForRow 期间您检查索引路径是否相同,如果是,请勾选复选标记,如果不删除复选标记。 这样,当单元格被重用时,ui 设置将被刷新。

      此外,在取消选择/选择期间,仅对更改的行执行 reloadCellAtIndexPath/reloadItems 以避免再次重新加载所有单元格。

      编辑:

      嗯,我要改变的第一件事是,你在 photoManager.requestImage 块内的所有逻辑我会移到外面,因为这可能是一个异步方法。 其次,你没有在每个单元格中设置或删除复选标记,因为当它被重用时,这个方法会被调用。

      这只是一个例子:

      func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
          guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoCellReuseIdentifier, for: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
          let requestOptions = PHImageRequestOptions()
          requestOptions.isSynchronous = true
          requestOptions.isNetworkAccessAllowed = true
          requestOptions.deliveryMode = .highQualityFormat
      
          photoManager.requestImage(for: photoAssets![indexPath.row], targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions, resultHandler: { (image, nil) in
              cell.photoView.image = image
              if indexPath.row == 0 && self.isFirstLoad {
                  self.selectedImageView.image = image
              }
          })
      
          if indexPath.row == 0 && self.isFirstLoad {
                  collectionView.selectItem(at: indexPath, animated: false, scrollPosition: UICollectionViewScrollPosition.bottom)
                  self.isFirstLoad = false
              }
      
          if cell.isSelected { // dont remember if this is the correct method
              cell.setupCheckmarkBanner()
          } else {
              cell.removeCheckmarkBanner()
          }
      
          return cell
      }
      

      【讨论】:

      • 如果您重新加载选定的单元格,则复选标记将消失。我使用了您的策略,但该集合仍然出现随机复选标记。
      • 您是否设置了所选索引路径的标志并确保删除或添加 cellForRow 中的复选标记?如果选择 { add },您不能只做,您需要拥有 else 并确保即使它不存在,也要删除复选标记。
      • 问题是 checkmarkBannerImageView 在删除时为零,即使在初始化它并将其添加到子视图之后,所以当 removeCheckmark 被调用时,它会在 nil 图像视图上调用它,所以复选标记保持在那里并且什么都没有得到-选择。也许我们可以聊天,我会告诉你发生了什么。
      • 你能复制/粘贴你的 cellForRow 函数的代码吗?
      • 查看我对帖子的编辑以获取更新的代码。给你
      【解决方案3】:

      我想通了!必须在出队后完成...

      import UIKit
      import Photos
      
      class PhotosViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
      
      let selectedImageView = UIImageView()
      var photoAssets: PHFetchResult<PHAsset>?
      let photoManager = PHImageManager.default()
      var selectedIndexPath: IndexPath = IndexPath(row: 0, section: 0)
      
      let collectionView: UICollectionView = {
          let collectionViewFlowLayout = UICollectionViewFlowLayout()
          collectionViewFlowLayout.sectionInset = UIEdgeInsetsMake(0, 2, 0, 2)
          collectionViewFlowLayout.minimumInteritemSpacing = 0
          collectionViewFlowLayout.minimumLineSpacing = 2
          let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout)
          collectionView.backgroundColor = .white
          return collectionView
      }()
      
      private let photoCellReuseIdentifier = "photoCell"
      var photos = [UIImage]()
      
      override func viewDidLoad() {
          super.viewDidLoad()
          view.backgroundColor = .white
          view.addSubview(selectedImageView)
          view.addSubview(collectionView)
          collectionView.dataSource = self
          collectionView.delegate = self
          fetchAssets()
          selectedImageView.anchor(top: view.topAnchor, left: view.leadingAnchor, bottom: collectionView.topAnchor, right: view.trailingAnchor, paddingTop: 0, paddingLeft: 2, paddingBottom: 2, paddingRight: 2, width: 0, height: view.bounds.height/1.5)
          collectionView.anchor(top: nil, left: view.leadingAnchor, bottom: view.bottomAnchor, right: view.trailingAnchor, paddingTop: 5, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
          collectionView.register(PhotosCell.self, forCellWithReuseIdentifier: photoCellReuseIdentifier)
       }
      
      private func fetchAssets() {
          guard let cameraRollPhotoCollection = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil).firstObject else { return }
          let assetOptions = PHFetchOptions()
          let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
          assetOptions.sortDescriptors = [sortDescriptor]
          photoAssets = PHAsset.fetchAssets(in: cameraRollPhotoCollection, options: assetOptions)
      
          let requestOptions = PHImageRequestOptions()
          requestOptions.isSynchronous = true
          requestOptions.isNetworkAccessAllowed = true
          requestOptions.deliveryMode = .highQualityFormat
      
          guard let photoAssets = photoAssets else { return }
          let photoAssetsCount = photoAssets.count - 1
      
          for assetIndex in 0..<photoAssetsCount {
          photoManager.requestImage(for: photoAssets[assetIndex], targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFill, options: requestOptions, resultHandler: { (image, nil) in
              guard let image = image else { return }
              self.photos.append(image)
          })
      
          }
      
      }
      
      func numberOfSections(in collectionView: UICollectionView) -> Int {
          return 1
      }
      
      func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
          return photos.count
      }
      
      func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
          guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: photoCellReuseIdentifier, for: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
          cell.photoView.image = photos[indexPath.row]
          if indexPath == selectedIndexPath {
              cell.setupCheckmarkBanner()
          }
          else {
              cell.removeCheckmarkBanner()
          }
      
          return cell
      }
      
      func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
          let width = view.bounds.size.width/3 - 3
          let height = view.bounds.size.height/5
          return CGSize(width: width, height: height)
      }
      
      func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
          if collectionView.indexPathsForVisibleItems.contains(indexPath) {
              guard let deselectedCell = collectionView.cellForItem(at: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
              deselectedCell.removeCheckmarkBanner()
          }
          else {
              collectionView.deselectItem(at: indexPath, animated: false)
          }
      }
      
      func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
          guard let selectedCell = collectionView.cellForItem(at: indexPath) as? PhotosCell else { fatalError("Couldn't return a photo cell") }
          selectedIndexPath = indexPath
          selectedCell.setupCheckmarkBanner()
      }
      

      }

      扩展 PhotosViewController: ImageDismissalDelegate { func sendProfilePictureImage(图片: UIImage) {

      }
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-27
        • 2011-10-26
        • 1970-01-01
        • 1970-01-01
        • 2012-11-19
        • 1970-01-01
        • 2017-09-19
        相关资源
        最近更新 更多