killvak
killvak

Reputation: 96

While fast scrolling collectionview the first row data duplicate in the last row

i wanted to make an application with a design that looks like the app store so i followed let's build that app tutorial on how to build it and the result was excellent, when i tested it on my device it seem that when i fast scroll the collection-view the data that's in the first row take place on the last row and when scroll fast up again, the data that supposed to be in the last row i found it in the first row and when i scroll left and right in the row when the cell go off the screen it re-update to the right data but when fast scroll up and down fast again the data between the first row and last row go crazy. i added image to the case in the end of the code.i spent 5 days trying to fix this but no luck at all i tried alot of solution like reset the data in the cell to nil before reseting it and alot other u will find it in the code but no luck , I really appreciate any help you can provide, Thanks

*update after @Joe Daniels answer all the data are staple and work fine except the images it still go crazy when fast scrolling but it return after 7/8 sec of stopping scrolling to the right image

first class that contain the vertical collectionview i made the width of the cell equal the width of the view , i tried the cell.tag == index-path.row solution but it didn't work

        class HomePageVC: UIViewController  ,  UICollectionViewDataSource , UICollectionViewDelegate , UICollectionViewDelegateFlowLayout ,SWRevealViewControllerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()
     mainProductsRow.delegate = self
    mainProductsRow.dataSource = self
}


   func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

            if let count = productCategory?.count {
            return count + 1
        }
        return 0

}

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

    if indexPath.row == 0 {
        let   cell  = collectionView.dequeueReusableCell(withReuseIdentifier: LargeHomeCategoriesCell.identifier, for: indexPath) as! LargeHomeCategoriesCell
        cell.categoriesHomePageVC = self
        cell.catIndexPath = indexPath.row
        cell.productCategories = productCategory
        cell.seeMore.addTarget(self, action: #selector(self.seeMoreCat(_:)), for: UIControlEvents.touchUpInside)
        return cell
    }
        let   cell  = collectionView.dequeueReusableCell(withReuseIdentifier: "RowCell", for: indexPath) as! HomeCategoriesCell

        cell.categoriesHomePageVC = self
        cell.catIndexPath = indexPath.row
    cell.seeMore.tag = (indexPath.row - 1 )
    cell.seeMore.addTarget(self, action: #selector(self.seeMore(_:)), for: UIControlEvents.touchUpInside)
 //   cell.tag = indexPath.row - 1
    cell.productCategory = nil
    //if cell.tag == indexPath.row - 1{
        cell.productCategory = productCategory?[indexPath.row - 1 ]

 //   }
        return cell


}

**Second Class that contain the horizontal collectionview that is in the first collectionview cell ** in the cell-for-item-At-index-Path i printed the index-path.row when the view-load it printed 0 , 1 ,2 and didn't print the last index '3' and the same thing happen again when i scroll to the end of the collection view

class HomeCategoriesCell: UICollectionViewCell , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout , UICollectionViewDelegate{




@IBOutlet weak var seeMore: UIButton!
@IBOutlet weak var categorytitle: UILabel!
@IBOutlet weak var productsCollectionView: UICollectionView!

let favFuncsClass = FavItemsFunctionality()
let onCartFuncsClass = OnCartFunctionality()

var productCategory : ProductCategories? {
    didSet {
        if let categoryTitle = productCategory?.name {
            categorytitle.text = categoryTitle
        }
    }

  override func awakeFromNib() {
    recivedNotification()

    productsCollectionView.delegate = self
    productsCollectionView.dataSource = self
    productsCollectionView.backgroundColor = UIColor.clear
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if let count = productCategory?.products?.count {
        return count
    }
    return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    print(indexPath.row)
    let   cell  = collectionView.dequeueReusableCell(withReuseIdentifier: "HProductCell", for: indexPath) as! HomeProductCell
    cell.tag = indexPath.row

    cell.productImage.image = #imageLiteral(resourceName: "PlaceHolder")
    cell.productTitle.text = nil
    cell.productPrice.text = nil
    cell.discountLabel.text = nil
    cell.preDiscountedPrice.text = nil
    cell.favButton.setImage(UIImage(named:"Heart_icon"), for: UIControlState.normal)
    cell.addToCart.setImage(UIImage(named:"cart"), for: UIControlState.normal)
    cell.configCell(products: nil)
    if cell.tag == indexPath.row {
        cell.configCell(products: productCategory?.products?[indexPath.item])
    }
    cell.catNum = indexPath.row

    return cell
}
    // Thanks to Joe Daniels i added this code and my nightmare become way less scary :P 
      override func prepareForReuse() {
    super.prepareForReuse()
    productsCollectionView.reloadData()
  }

}

Product Cell i tried the prepare-For-Reuse() and reseted all the data to nil but still didn't work

  class HomeProductCell: UICollectionViewCell {

func configCell(products :productDetails?){
      if let title = products?.name {
        self.productTitle.text = title
    }else {  self.productTitle.text = nil}

    if let price = products?.price {
        self.productPrice.text = "\(price)"
    }else { self.productPrice.text = nil }

    }

  override func prepareForReuse() {
    super.prepareForReuse()
    self.productImage.image = #imageLiteral(resourceName: "PlaceHolder")
    productTitle.text = nil
    productPrice.text = nil
    discountLabel.text = nil
    preDiscountedPrice.text = nil
    favButton.setImage(UIImage(named:"Heart_icon"), for: UIControlState.normal)
    addToCart.setImage(UIImage(named:"cart"), for: UIControlState.normal)

}

i took a screen shoots of the case you can find it here

Upvotes: 1

Views: 722

Answers (2)

killvak
killvak

Reputation: 96

i Found the Perfect Solution that worked for me as magic after 15 days of suffering xD i used this library (https://github.com/rs/SDWebImage).

To use it in swift put this line in your bridging Header

#import <SDWebImage/UIImageView+WebCache.h>

And in the collectionViewCell i used this line

self.productImage.sd_setImage(with: myUrl , placeholderImage: UIImage(named:"yourPlaceHolderImage")

Upvotes: 1

Joe Daniels
Joe Daniels

Reputation: 1706

The inner collectionView has no way of knowing that it went off screen. do a reload in prepareForReuse

Upvotes: 0

Related Questions