Reputation: 41
Note: I have tried all matching questions from stack overflow but none helped to fix this issue/scenario hence posting.
I have a collection view in which i have number of cells where each cell has one image view. Each cell will have different array of images which i need to show one after another through fade effect. First time it shows correctly however when i scroll then problems arises. First cell's image/s displays in any other cell. Images shuffles.
extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
// let image = cell.viewWithTag(1) as! UIImageView
// let imgArr = imagesArray[indexPath.row]
// image.downloadImageAndAnimateIt(imageStringArray: imgArr)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = self.collectionView.bounds.size.width / 2 - 5
return CGSize(width: size, height: size - 5)
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let image = cell.viewWithTag(1) as! UIImageView
let imgArr = imagesArray[indexPath.row]
image.downloadImageAndAnimateIt(imageStringArray: imgArr)
}
}
//=========== END of view controller
extension UIImageView {
func downloadImageAndAnimateIt(imageStringArray:[String]){
var imagesArray = [UIImage]()
for imgStr in imageStringArray{
imagesArray.append(UIImage(named: imgStr)!)
}
let dispatchGroup = DispatchGroup()
// dispatchGroup.notify(queue: DispatchQueue.main) {[weak self] in
// self?.animationImages = imagesArray.compactMap({$0})
// self?.animationDuration = 5.0
// self?.startAnimating()
// }
var photoCount = 0
var timer = Timer()
dispatchGroup.notify(queue: DispatchQueue.main) {[weak self] in
timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true, block: { (timer) in
if (photoCount < imagesArray.count - 1){
photoCount = photoCount + 1;
}else{
photoCount = 0;
}
if let this = self {
UIView.transition(with: this, duration: 2.0, options: .transitionCrossDissolve, animations: {
this.image = imagesArray[photoCount]
}, completion: nil)
}
})
}
}
}
Images should not shuffle and those should remain on the same cell as it was before scrolling.
Upvotes: 4
Views: 1684
Reputation: 4470
You have to create CustomCollectionCell class to seperate your code try using following way and also for download image you can use SDWebImage
extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath) as! CollectionViewCell
cell.imgView.image = nil
cell.createImages(imageStringArray: imagesArray[indexPath.row])
cell.configureTimer()
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = self.collectionView.bounds.size.width / 2 - 5
return CGSize(width: size, height: (size * 1.5) - 5)
}
}
class CollectionViewCell: UICollectionViewCell {
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
var imageArray:[UIImage] = []
var timer = Timer()
var photoCount: Int = 0
@IBOutlet weak var imgView: UIImageView!
func createImages(imageStringArray:[String])
{
self.imageArray.removeAll()
for imgStr in imageStringArray
{
self.imageArray.append(UIImage.init(named: imgStr) ?? UIImage.init())
}
}
func configureTimer()
{
self.timer.invalidate()
self.imgView.image = self.imageArray[self.photoCount] //Set Default Image First Time
self.timer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: true, block: { (timer) in
if (self.photoCount < self.imageArray.count - 1){
self.photoCount = self.photoCount + 1;
}else{
self.photoCount = 0;
}
if let imageView = self.imgView {
UIView.transition(with: imageView, duration: 2.0, options: .transitionCrossDissolve, animations: {
imageView.image = self.imageArray[self.photoCount]
}, completion: nil)
}
})
}
}
Upvotes: 2
Reputation: 698
There are many cases you will need to handle while downloading an image and showing it inside UITableView
/ UICollectionView
cell:
UIImageView
on main thread.I will strongly recommend to use one of the libraries for this like SDWebImage
Upvotes: 1
Reputation: 1396
What is actually happening here is collectionView is reusing previous cell so image from previous cell is loaded in new cell when image is under downloading to remove this behavior you need to set a placeholder image Or you may set image empty
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
let image = cell.viewWithTag(1) as! UIImageView
image.image = "placeholderImage" // replace it with your place holder image
//Or
// image.image = UIImage()
let imgArr = imagesArray[indexPath.row]
image.downloadImageAndAnimateIt(imageStringArray: imgArr)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = self.collectionView.bounds.size.width / 2 - 5
return CGSize(width: size, height: size - 5)
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
}
Upvotes: 0