gpt4 book ai didi

ios - UICollectionView 没有通过 cellForItemAt 正确更新所有单元格

转载 作者:行者123 更新时间:2023-12-01 21:59:22 27 4
gpt4 key购买 nike

我有以下设置:UICollectionView使用自定义单元格,用户可以在其中选择多个单元格,然后执行一些繁重的图像操作。现在我尝试使用该操作的结果更新用户选择的选定单元格,这将由子类自定义单元格的函数产生。对于所有可见单元格,该函数在用户按下按钮时调用,对于所有其他单元格,这通过 cellForItemAt 发生。为了最有效率。

但是,我现在面临的问题是,可见单元格都已更新,但是在滚动可见单元格之后或之前的单元格之后 不更新 通过 cellForItemAt但仅在来回滚动时。请参阅随附的视频。

出于演示目的,我只显示绿色 UIView用于图像操作。因为该操作需要大量资源,我不能使用任何 UICollectionView重载数据 或类似的,因为它们会取消选择选定的单元格,并且手动重新选择会导致闪烁。

View Controller

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!

// data source
var items: [String] = ["Lynna", "Vickie", "Emmerich", "Chere", "Patrizius", "Micky", "Sarena", "Jewell", "Audrye", "Rockwell", "Lari", "Travis", "Ber", "Oneida", "Bethanne", "Geri", "Gray", "Wolfie", "Hallsy", "Vanna", "Aline", "Winslow", "Amelita", "Janek", "Samuel", "Jaclin", "Dick", "Jeanine", "Brandy", "Munroe", "Felice", "Melonie", "Esta", "Bria", "Kenon", "Roarke", "Gerry", "Carmel", "Conrado", "Jaquelin", "Avrit", "Noam", "Kleon", "Edith", "Carine", "Jackie", "Franni", "Riccardo", "Theda", "Virgina", "Carleen", "Gregorio", "Taylor", "Ellsworth", "Adolphus", "Annabella", "Natalya", "Celina", "Cathrine", "Evie", "Gasper", "Aguste", "Jory", "Farrell", "Natasha", "Deborah", "Pietro", "Lucila", "Yuri", "Micheil", "Claus", "Nelson", "Elisa", "Alfons", "Nicolea", "Sofia", "Geordie", "Anette", "Myrtice", "Tami", "Lucien", "Brigida", "Claire", "Brennan", "Kendal", "Jillana", "Adelaida", "Charles", "Mart", "Hastie", "Dewain", "Heida", "Karisa", "Arleyne", "Margi", "Brent", "Natalie", "Ashton", "Teodorico", "Prentice", "Rolando", "Tootsie", "Fonz", "Tremayne", "Bernardo", "Guthrie", "Hendrick", "Constantina", "Lin", "Reece", "Horace", "Celka", "Amata", "Dunc", "Franchot", "Niko", "Janna", "Jacklyn", "Eddy", "Ashely", "Angelica", "Pinchas", "Krishnah", "Edmon", "Darnell", "Alyson", "Pearle", "Ashla", "Chickie", "Ada", "Elane", "Bethanne-Two", "Lon", "Marlin", "Karissa", "Ellswerth", "Lisbeth", "Cortie", "Lucille", "Lissa", "Markos", "Alys", "Orrin", "Nancy", "Pepe", "Lauren", "Wyndham", "Belle", "Gordie", "Marcille", "Idaline", "Hillary", "Enrique", "Murielle", "Juliann", "Beatrisa", "Lavinia", "Noni", "Justino", "Hasty", "Sile", "Kiley", "Shepard", "Nickie", "Ly", "Dannel", "Tressa", "Merci", "Rog", "Frans", "Bernita", "Ginnie", "Niko-Two", "Sheilakathryn", "Whitman", "Kendell", "Florenza", "Marybeth", "Drusi", "Paulina", "Fina", "Moria", "Jacobo", "Rowan", "Mariejeanne", "Luelle", "Vicki", "Auria", "Trisha", "Ken", "Carline", "Dorry", "Forrester", "Wylie", "Elset", "Francyne", "Bondy", "Demott", "Erik", "Elenore", "Correy", "Isadora", "Mason", "Barris", "Marlee", "Haslett", "Lorette", "Arlyn", "Genna", "Trude", "Parnell", "Albina", "Spencer", "Lefty", "Luigi", "Winnie", "Torie", "Zita", "Bert", "Danyelle", "Aldis", "Rivy", "Niels", "Monte", "Sandy", "Georgeta", "Durante", "Cobbie", "Kathryn", "Dinnie", "Fanchon", "Say", "Ethelred", "Vick", "Betteanne", "Orazio", "Mannie", "Jinny", "Kerrin", "Abagail", "Reyna", "Tomlin", "Shelton", "Noble", "Massimiliano", "Madel", "Cayla", "Mathias", "Tod", "Liana", "Celia", "Antoni", "Ruthann", "Irvine", "Leisha", "Geri-Two", "Marlie", "Pascale", "Latia", "Minne", "Arlette", "Rhys", "Flint", "Sollie", "Hinda", "Igor", "Marcella", "Wilma", "Marijo", "Marika", "Pooh", "Roland", "Sergent", "Fawnia", "Valaree", "Evonne", "Angeline", "Welbie", "Mace", "Niles", "Grannie", "Berenice", "L;urette", "Nert", "Rheba", "Cristie", "Lazar", "Amil", "Yanaton", "Luella", "Herold", "Enrique-Two", "Joanna", "Dom", "Crista", "Ellyn", "Ema", "Romona", "Dona", "Madelina", "Nevsa", "Conway", "Laverna", "Orion", "Leighton", "Earle"]

// stores the selected items
var selectedItems = [String]()

var applyImageOperation = false

override func viewDidLoad() {
super.viewDidLoad()

// Set up collection view
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
collectionView.collectionViewLayout = layout

collectionView.allowsMultipleSelection = true
collectionView.delegate = self
collectionView.dataSource = self
self.collectionView!.register(MyCustomCell.self, forCellWithReuseIdentifier: "CELL")
self.collectionView!.contentInset = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 6)
}

@IBAction func btnSelectAllPressed(_ sender: Any) {
// Add all items to the seleted array
selectedItems = [String]() // empty the current selection first
for item in items {
selectedItems.append(item)
}

// Update the collection view visually by selecting all cells
for i in 0..<collectionView.numberOfItems(inSection: 0) {
collectionView.selectItem(at: IndexPath(row: i, section: 0), animated: false, scrollPosition: [])
}
}

@IBAction func btnApplyImageOperationPressed(_ sender: Any) {
// set image operation mode true if we have items selected
if selectedItems.count > 0 {
applyImageOperation = true
}

// All visible cells should call activateImageOperationMode() - all others will do in cellForItem
for visibleCell in collectionView.visibleCells {
if let cell = visibleCell as? MyCustomCell {
if let name = cell.titleLabel.text {
if selectedItems.contains(name) {
cell.activateImageOperationMode()
}
}
}
}
}
}




extension ViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: ((collectionView.frame.width-12)/3), height: ((collectionView.frame.width-12)/3))
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL", for: indexPath) as! MyCustomCell
cell.titleLabel.text = items[indexPath.row]

// if image operation is not active, we don't show / remove the view
if !applyImageOperation {
cell.deactivateImageOperationMode()
}
// if image operation is active, we show the view for all selected items
else {
// Check if cell is selected
if selectedItems.contains(items[indexPath.row]) {
cell.activateImageOperationMode()
}
// If cell is not selected
else {
cell.deactivateImageOperationMode()
}
}

return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Add item to selectedItems
if !selectedItems.contains(items[indexPath.row]) {
selectedItems.append(items[indexPath.row])
}
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
// Remove item from selectedItems
if selectedItems.contains(items[indexPath.row]) {
selectedItems.removeAll{ $0 == items[indexPath.row] }
}
}
}

我的自定义单元
import UIKit

class MyCustomCell: UICollectionViewCell {

let titleLabel: UILabel = {
let l = UILabel()
l.translatesAutoresizingMaskIntoConstraints = false
l.text = "n/a"
l.textColor = .red
l.textAlignment = .center
return l
}()

let bgColor: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .lightGray
return v
}()

var myImageOperationView: UIView?



required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.commonInit()
}

override init(frame: CGRect) {
super.init(frame: frame)
self.commonInit()
}

func commonInit(){
// Configure Selection Background View
selectedBackgroundView = {
let view = UIView()
view.backgroundColor = .red
return view
}()

// Set std BG color
contentView.addSubview(bgColor)
bgColor.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6).isActive = true
bgColor.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -6).isActive = true
bgColor.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 6).isActive = true
bgColor.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -6).isActive = true

// Setup label
bgColor.addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: bgColor.topAnchor, constant: 0).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: bgColor.bottomAnchor, constant: 0).isActive = true
titleLabel.leftAnchor.constraint(equalTo: bgColor.leftAnchor, constant: 0).isActive = true
titleLabel.rightAnchor.constraint(equalTo: bgColor.rightAnchor, constant: 0).isActive = true
}

func activateImageOperationMode() {
if myImageOperationView == nil {
// HERE WOULD BE SOME HEAVY IMAGE OPERATION
// Adding this view is just a placeholder for demonstration
myImageOperationView = UIView()
myImageOperationView!.translatesAutoresizingMaskIntoConstraints = false
myImageOperationView!.backgroundColor = .green
bgColor.addSubview(myImageOperationView!)
myImageOperationView!.topAnchor.constraint(equalTo: bgColor.topAnchor, constant: 0).isActive = true
myImageOperationView!.bottomAnchor.constraint(equalTo: bgColor.bottomAnchor, constant: 0).isActive = true
myImageOperationView!.leftAnchor.constraint(equalTo: bgColor.leftAnchor, constant: 0).isActive = true
myImageOperationView!.rightAnchor.constraint(equalTo: bgColor.rightAnchor, constant: 0).isActive = true

// bring label to top
bgColor.bringSubviewToFront(titleLabel)
}
}

func deactivateImageOperationMode() {
if myImageOperationView != nil {
myImageOperationView!.removeFromSuperview()
myImageOperationView = nil
}
}
}

显示行为的视频

enter image description here

最佳答案

UICollectionView 默认为 prefetchingEnabled == YES ,这意味着 Collection View 将在需要显示单元格之前请求它们。如果应用程序的状态发生变化,使得已经获取的单元格需要以不同的方式显示,您可以实现 collectionView:willDisplayCell:forItemAtIndexPath: 更新单元格的方法。

看起来这正是您的问题……您打开了一个应该改变单元格外观的功能,但是已获取但不可见的单元格不会得到更新。实现 collectionView:willDisplayCell:forItemAtIndexPath:应该解决问题。

关于ios - UICollectionView 没有通过 cellForItemAt 正确更新所有单元格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60495793/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com