我想在选定的单元格中添加复选标记。如果随后取消选择该单元格(因此选择了另一个单元格),我想删除复选标记。顶部图像视图独立于集合视图,表示用户相机胶卷中的选定单元格。集合视图的数据源是从PHAssets获取的图像列表。
问题是,如果我不在indexPath重新加载项目,则取消选择的单元格复选标记不会被删除。此外,如果我滚动浏览集合视图,我会看到来自我甚至没有点击的单元格的随机复选标记。我假设它与重复使用细胞有关。有人可以帮帮我吗?
以下是来自视图控制器和单元格的代码片段......
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
}
}
答案 0 :(得分:0)
你必须保存所选单元格的索引路径(在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
}
答案 1 :(得分:0)
为了避免重用单元格中不需要的内容,您可以覆盖prepareForReuse()方法,并在那里执行所有设置工作(例如隐藏复选标记)
答案 2 :(得分:0)
我明白了!它必须在出列后完成......
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){
}
}