-1

I am implementing general collectionView in a viewController to populate data and the collection view has 2 columns and the number of rows depend on the data, and now my collectionView looks like this.

Normal collectionView:

enter image description here

This is what I have implemented in my app as you can see it is a normal collection view with n rows and 2 columns. But, our requirement is

Business requirement Image:

There is the custom view which is added after every 2 rows and it is static with a two labels and a button...

I don't know if it is possible and how to achieve this... And after searching for some time I learned that we can do this by using DecoratorViews and I don't know what are those and how to use them.. If anyone have any idea on how to achieve this kind of layout, please guide me..

variables:

let columnsPerRow = 2
let addAfterRows = 5
var cellToShowWithAdds = 0

Function:

func getCategoryProducts() {

    var id = Int()
    var categoryProductsAPI = ""
    if self.brandId != nil {
        id = self.brandId!
        if self.selectedSubCategoryId != nil {
            categoryProductsAPI = "\(API.CATEGORY_BRAND_FILTER)\(self.selectedSubCategoryId!)\(API.BRAND_ID )\(id)"
        } else {
            categoryProductsAPI = "\(API.CATEGORY_BRAND_FILTER)\(self.categoryId!)\(API.BRAND_ID )\(id)"
        }
    } else {
        if self.selectedSubCategoryId != nil {
            id = self.selectedSubCategoryId!
        } else {
            id  = self.categoryId!
        }
        categoryProductsAPI = "\(API.CATEGORY_PRODUCTS)\(id)"
    }
    print(categoryProductsAPI)
    self.cellToShowWithAdds = 0
    self.categoryProductsData = []
    self.loadingView.isHidden = false
    self.loadingActivityIndicator.animate()
    ServiceManager.callGetAPI(url: categoryProductsAPI, view: self, closure: { response in
        self.loadingView.isHidden = true
        self.loadingActivityIndicator.stopAnimating()
        guard let categoryData = response?.result.value  else {return}
        if let categories = categoryData as? [[String : Any]] {
            for product in categories {
                let productName = product["product_name"] as! String
                let productId = product["product_id"] as! String
                let productBrand = product["product_brand"] as! String
                guard let productOffPercent = product["product_sale_of"] else { return }
                let productImage = product["product_image"] as! String
                let productPrice = product["product_price"] as! String
                let productSepcialPrice = product["product_special_price"] as! String
                var newProductPrice = String()
                if productSepcialPrice == "Rs.0.00" {
                    newProductPrice = productPrice
                } else {
                    newProductPrice = productSepcialPrice
                }

                self.categoryProductsData.append(ProductDetails(productID: productId, productName: productName, productPrice: productPrice, productSpecialPrice: newProductPrice, productOff: productOffPercent, productBrand: productBrand, productImageURL: productImage))
            }
            let quot = (self.categoryProductsData.count/(self.columnsPerRow * self.addAfterRows))
            self.cellToShowWithAdds = self.categoryProductsData.count + quot + 1
            DispatchQueue.main.async {
                self.categoryProductsCollection.reloadData()
            }
        }
    }, errorAction: {
        self.loadingView.isHidden = true
        self.loadingActivityIndicator.stopAnimating()
    }, okAction: {
        self.view.setNeedsLayout()
        self.viewWillAppear(true)
    })
}

DataSource methods:

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

    return cellToShowWithAdds        
}

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

   if indexPath.row % 5 != 0 {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductDisplayCell
            let productId = Int(categoryProductsData[indexPath.item].productID)
            cell.tag = productId!
            if categoryProductsData[indexPath.item].productImageURL != "" {
                if let productImage = URL(string: categoryProductsData[indexPath.item].productImageURL) {
                    cell.productImage.getImageWith(imageUrl: productImage)
                }
            } else {
                cell.productImage.image = nil
            }
            cell.productNameLabel.text = categoryProductsData[indexPath.item].productName
            cell.sellerNameLabel.text = categoryProductsData[indexPath.item].productBrand
            cell.offerPercentLabel.text = "\(categoryProductsData[indexPath.item].productOff)% Off"

            if "\(categoryProductsData[indexPath.item].productOff)" == "" || "\(categoryProductsData[indexPath.item].productOff)" == "100" || "\(categoryProductsData[indexPath.item].productOff)" == "0" {
                cell.offerPercentLabel.isHidden = true
            } else {
                cell.offerPercentLabel.isHidden = false
            }

            if categoryProductsData[indexPath.item].productSpecialPrice != "Rs.0.00" {
                if categoryProductsData[indexPath.item].productPrice == categoryProductsData[indexPath.item].productSpecialPrice  {
                    cell.originalPriceLable.isHidden = true
                    cell.offerPriceLabel.isHidden = false
                } else {
                    cell.originalPriceLable.isHidden = false
                    cell.offerPriceLabel.isHidden = false
                }
            } else if categoryProductsData[indexPath.item].productSpecialPrice == "Rs.0.00" {
                cell.originalPriceLable.isHidden = true
                cell.offerPriceLabel.isHidden = true
            } else {
                cell.originalPriceLable.isHidden = false
                cell.offerPriceLabel.isHidden = false
            }
            cell.originalPriceLable.attributedText = categoryProductsData[indexPath.item].productPrice.strikeThrough()
            cell.offerPriceLabel.text = categoryProductsData[indexPath.item].productSpecialPrice
            return cell
        } else {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "formCollectionCell", for: indexPath) as! PostRequirementCellCollectionViewCell
            return cell
        }       
}
  • 2
    Great explanation and step-by-step tutorial [provided by matt](https://stackoverflow.com/a/39218108/3397217), and a [visual example by Larry](https://stackoverflow.com/a/14149066/3397217) – LinusGeffarth Jan 02 '19 at 08:20
  • 2
    Possible duplicate of [UICollectionView Decoration View](https://stackoverflow.com/questions/12810628/uicollectionview-decoration-view). Literally the first hit in Google when searching for *DecoratorViews UICollectionView*. Do your research! – LinusGeffarth Jan 02 '19 at 08:20
  • You could add a header to your collectionview, or you could create a custom cell (the one that has a blue background) and in `cellForItemAt` check if it is the 2nd row and return this custom cell. Also, return its size in `sizeForItemAt` – Marwen Doukh Jan 02 '19 at 08:25
  • This can be an another cell itself. – TheTiger Jan 04 '19 at 05:17

1 Answers1

3

My Code should be explanatory. I have set some values in viewdidload to get the kind of view you require.

Please see screenshot

import UIKit

class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

@IBOutlet weak var collectionView : UICollectionView!

let totalProducts = 21
let columnsPerRow = 2
let addAfterRows = 2

var celltoShowWithAds = 0

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    let quot = (totalProducts/(columnsPerRow * addAfterRows))
    print(quot)
    celltoShowWithAds = totalProducts + quot + 1

    collectionView.register(UINib(nibName: "CollectionItemCell", bundle: nil), forCellWithReuseIdentifier: "CollectionItemCell")

    collectionView.register(UINib(nibName: "CollectionAdvertisementCell", bundle: nil), forCellWithReuseIdentifier: "CollectionAdvertisementCell")

    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.reloadData()
    //collectionView.backgroundColor = UIColor.blue
}

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

}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if indexPath.row == 0{
        let myCell:CollectionAdvertisementCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionAdvertisementCell", for: indexPath) as! CollectionAdvertisementCell
        return myCell as CollectionAdvertisementCell;

    }else if indexPath.row % 5 == 0{
        let myCell:CollectionAdvertisementCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionAdvertisementCell", for: indexPath) as! CollectionAdvertisementCell

        return myCell as CollectionAdvertisementCell;
    }else{
        let myCell:CollectionItemCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionItemCell", for: indexPath) as! CollectionItemCell

        return myCell as CollectionItemCell;
    }



}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    if indexPath.row == 0{
        return CGSize(width: view.frame.width, height: 0.0)
    }else if indexPath.row % 5 == 0 {
        return CGSize(width: view.frame.width, height: 80.0)
    }else{
        return CGSize(width: view.frame.width/CGFloat(columnsPerRow), height: 200.0)
    }

}




//Use for interspacing
func collectionView(_ collectionView: UICollectionView,
                    layout collectionViewLayout: UICollectionViewLayout,
                    minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}

func collectionView(_ collectionView: UICollectionView, layout
    collectionViewLayout: UICollectionViewLayout,
                    minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 0
}


/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destination.
    // Pass the selected object to the new view controller.
}
*/

}
Yogesh Tandel
  • 1,738
  • 1
  • 19
  • 25