Two Collection Views in One View Controller iOS - ios

I have two collection Views in One View Controller, First Collection View have class CollectionCellA with imageA as UIImageView! and labelA as UILabel!. Similarly Second Collection View with class CollectionCellB with imageB and labelB. I tried to run with following swift code but it show just blank(white) screen.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var imageArroy = [UIImage(named: "1"), UIImage(named: "2"), UIImage(named: "3"), UIImage(named: "5"), UIImage(named: "6")]
var imageArroyB = [UIImage(named: "a"), UIImage(named: "b"), UIImage(named: "c"), UIImage(named: "d"), UIImage(named: "e")]
var labelA: ["Electronics", "Cars", "Pets", "Mobiles", "Food"]
var labelB: ["UK", "Ireland", "India", "Germany", "Other EU"]
#IBOutlet weak var CollectionViewA: UICollectionView!
#IBOutlet weak var CollectionViewB: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
CollectionViewA.delegate = self
CollectionViewB.delegate = self
CollectionViewA.dataSource = self
CollectionViewB.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return 0 // Replace with count of your data for collectionViewA
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
// Set up cell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
// ...Set up cell
return cellB
}
}

This code works for Two Collection View in One View Controller with images and label.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return imageArroy.count
}
return imageArroyB.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
cellA.imageA.image = imageArroyB[indexPath.row]
cellA.labelA.text = labelA[indexPath.row]
// Set up cell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
cellB.imageB.image = imageArroyB[indexPath.row]
cellB.labelB.text = labelB[indexPath.row]
// ...Set up cell
return cellB
}
}

For me below code works like a charm . you should send/assign value in cellForItemAt indexPath
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.CollectionViewA {
return imageArroy.count
}
return imageArroyB.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.CollectionViewA {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellA", for: indexPath) as! CollectionCellA
// Set up cell
cellA.lbl.text = labelA[indexPath.row]
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCellB", for: indexPath) as! CollectionCellB
// ...Set up cell
cellB.lbl.text = labelB[indexPath.row]
return cellB
}
}
}
class CollectionCellA : UICollectionViewCell {
#IBOutlet weak var lbl: UILabel!
}
class CollectionCellB : UICollectionViewCell {
#IBOutlet weak var lbl: UILabel!
}

Add two collection view and connect delegate and data source with view countroller,create collection view cell and connect with cell and outlets
#IBOutlet weak var collectionView2: UICollectionView!
#IBOutlet weak var collectionview1: UICollectionView!
var days = ["Sun","Mon","Tues","Wed","Thur","Frid","Sat"]
var dayTask = [String]()
var task = [["Sun1","Mon1","Tues1","Wed1","Thur1","Frid1","Sat1"],["Sun2","Mon2","Tue2","Wed2"],["Sun3","Mon3","Tues3","Wed3","Thur3","Frid3","Sat3"],["Sun4","Mon4"],["Sun5","Mon5","Tues5","Wed5","Thur5","Frid5","Sat5"],["Sun6","Mon6","Tues6","Wed6"],["Sun7","Mon7","Tues7","Wed7","Thur7"]]
override func viewDidLoad() {
super.viewDidLoad()
dayTask = task[0]
// Do any additional setup after loading the view.
}
Collection view data source and delgate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionview1{
return days.count
}else{
return dayTask.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell1", for: indexPath) as! CollectionViewCell1
if collectionView == collectionview1{
cell.label.text = days[indexPath.row]
let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 40)
collectionViewLayout?.invalidateLayout()
}else
{
let collectionViewLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
collectionViewLayout?.sectionInset = UIEdgeInsets(top: 10, left: 20, bottom: 0, right: 40)
collectionViewLayout?.invalidateLayout()
cell.label.text = dayTask[indexPath.row]
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == collectionview1{
dayTask = task[indexPath.row]
collectionView2.reloadData()
}
}

Related

UICollectionViewCell did select item not working

I have an issue with a collectionView inside a TableVieCell. When i tap on a collectionCell, didSelectItemAt doesn´t get called. I have a button in the collectionCell so i tried to disable the user interaction and enable the contentView userInteraction but it didn't work.
The red rectangle is the tableCell and the blue rectangle is the collecionView insede the table view cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "MedCellWithCollection") as? MedCellWithCollection{
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.white.withAlphaComponent(0.0)
cell.selectedBackgroundView = backgroundView
cell.setMedName(name: self.medCatalog[indexPath.row].nombre, uso: self.medCatalog[indexPath.row].uso , array: self.medCatalog[indexPath.row].enfermedades[0].aplicaciones , index: indexPath.row)
cell.layoutIfNeeded()
cell.layoutSubviews()
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
return cell
}
}
return UITableViewCell()
}
The tableCell
class MedCellWithCollection: UITableViewCell {
//Outlets
#IBOutlet weak var medText: UILabel!
#IBOutlet weak var uso: UILabel!
#IBOutlet weak var arrowIcon: UIImageView!
#IBOutlet weak var CollectionView: UICollectionView!
//Variables
var dosesType:[Aplicacion]?
override func awakeFromNib() {
super.awakeFromNib()
self.collectionViewSetUp()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setMedName(name: String, uso: String, array: [Aplicacion], index: Int){
self.medText.text = name
self.uso.text = uso
self.dosesType = array
self.CollectionView.reloadData()
}
}
extension MedCellWithCollection: UICollectionViewDataSource, UICollectionViewDelegate{
func collectionViewSetUp(){
self.CollectionView.delegate = self
self.CollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dosesType?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "doseColletion", for: indexPath as IndexPath) as? DoseCollection {
cell.setButtonConfig(doseType: self.dosesType![indexPath.row].metodo , index: indexPath.row)
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("tapped")
}
}
CollectionCell
import UIKit
class DoseCollection: UICollectionViewCell {
//Outlets
#IBOutlet weak var Button: Button!
//Variables
let constants = Constants()
func setButtonConfig(doseType: String, index: Int){
self.Button.titleLabel?.text = doseType
self.Button.backgroundColor = constants.COLOR_ARRAY[index]
}
override func layoutSubviews() {
super.layoutSubviews()
}
override func layoutIfNeeded() {
super.layoutIfNeeded()
}
}
Potential Solutions:
1) Should be Single Selection for tableView selection property, programmatically it can be done by tableView.allowsSelection = true
2) The class is not the UITableViewDelegate for that table view, though UITableViewController is supposed to set that automatically.
tableView?.delegate = self
3) If the problem arise with UITapGestureRecognizer:
let tap = UITapGestureRecognizer(target: self, action:Selector("dismissKeyboard"))
view.addGestureRecognizer(tap)
tap.cancelsTouchesInView = false
BOL :)
In my case, I want to change the background of the button in other words the background of the cell in the collection view:
class CustomCVCell: UICollectionViewCell {
override var isSelected: Bool {
didSet {
grayBackgroundViewWithImage.image =
isSelected ? UIImage(named: "") : UIImage()
}
}
In the main class where the collection view is stored create this variable:
class CustomViewController: UIViewController {
///save the indexPath of last selected cell
private var lastSelectedIndexPath: IndexPath? }
In viewDidLoad() set this value to false:
customCollectionView.allowsMultipleSelection = false
Further code in data source. In my case, the first cell should be is selected:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCVCell.cellID(),
for: indexPath) as! CustomCVCell
if indexPath.row == 0 {
lastSelectedIndexPath = indexPath
cell.isSelected = true
}
//update last select state from lastSelectedIndexPath
cell.isSelected = (lastSelectedIndexPath == indexPath)
return cell
}
Further code in the delegate:
///UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard lastSelectedIndexPath != indexPath else { return }
if let index = lastSelectedIndexPath {
let cell = collectionView.cellForItem(at: index) as! CustomCVCell
cell.isSelected = false
}
let cell = collectionView.cellForItem(at: indexPath) as! CustomCVCell
cell.isSelected = true
lastSelectedIndexPath = indexPath
}

2 Collection View in one View

I have this StoryBoard:
and this code in MainViewControler:
class TipViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView1: UICollectionView!
#IBOutlet weak var collectionView2: UICollectionView!
let tips = ["Jakość frytek nas nie zadawala", "Kolor frytek jest niesatysfakcjonujący", "LOT i reklamacja", "Olej nie spełnia naszych oczekiwań", "jakiś fajny"]
let tipsImages: [UIImage] = [UIImage(named: "a1.jpg")!, UIImage(named: "a2.jpg")!, UIImage(named: "a3.jpg")!, UIImage(named: "a4.jpg")!, UIImage(named: "a5.jpg")!]
let leaflets = ["AV-AddedValueFries-Ulotka", "AV-AddedValueFries-Ulotka 23112", "Ulotka", "Fajna ulotka"]
let leafletsImages: [UIImage] = [UIImage(named: "d1.jpg")!, UIImage(named: "d2.jpg")!, UIImage(named: "d3.jpg")!, UIImage(named: "d4.jpg")!]
override func viewDidLoad() {
super.viewDidLoad()
collectionView1.dataSource = self
collectionView1.delegate = self
collectionView2.dataSource = self
collectionView2.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tips.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView1.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as UICollectionViewCell
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
return cell
}
}
CellVC1:
class TipCollectionViewCellLeaflets: UICollectionViewCell {
// Outtlets
#IBOutlet weak var imgView1: UIImageView!
#IBOutlet weak var titleLabel1: UILabel!
}
CellVC2:
class TipCollectionViewCellLeaflets: UICollectionViewCell {
// Outtlets
#IBOutlet weak var imgView2: UIImageView!
#IBOutlet weak var titleLabel2: UILabel!
}
I have problem with:
1. in line:
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
I have error: "Value of type 'UICollectionViewCell' has no member 'titleLabel'" and "Value of type 'UICollectionViewCell' has no member 'imgView'"
How can I display data in the second CollectionView (collectionView2)?
UPDATE 1
WIth this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == collectionView1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as! TipCollectionViewCellTips
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as! TipCollectionViewCellLeaflets
cell.titleLabel2.text = leaflets[indexPath.item]
cell.imgView2.image = leafletsImages[indexPath.item]
return cell
}
}
There is no problem with compilation.
Now problem is in this code:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tips.count
}
Change your numberOfItem method to :-
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionView1{
return tips.count
}else{
return leaflets.count
}
Change your cellForItemAt method to :-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
Var cell = UICollectionViewCell()
if collectionView == collectionView1{
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as TipCollectionViewCellLeaflets
}else{
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as TipCollectionViewCellLeaflets
}
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == collectionView1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1 identifier", for: indexPath) as! TipCollectionViewCellTips
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
// set other properties
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2 identifier", for: indexPath) as! TipCollectionViewCellLeaflets
cell.titleLabel.text = tips[indexPath.item]
cell.imgView.image = tipsImages[indexPath.item]
// set other properties
return cell
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == collectionView1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as TipCollectionViewCellTips
cell.titleLabel1.text = tips[indexPath.item]
cell.imgView1.image = tipsImages[indexPath.item]
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell2", for: indexPath) as TipCollectionViewCellLeaflets
cell.titleLabel2.text = leaflets[indexPath.item]
cell.imgView2.image = leafletsImages[indexPath.item]
return cell
}
}
try this..
Change this linke into
let cell = collectionView1.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as UICollectionViewCell
to
let cell = collectionView1.dequeueReusableCell(withReuseIdentifier: "Cell1", for: indexPath) as TipCollectionViewCellLeaflets

First cell and last cell are changing each other in UICollectionView

I have MenuItemCollectionView and FoodItemColletionView and I am setting FoodItemCollectionView in MenuItemColletionViewCell.Error happened in first MenuItemCell and last MenuItemCell are changing each other.But sometimes they are appeared right place.I have no idea to fix this error
This is MenuItemCollectionView
func numberOfSections(in collectionView: UICollectionView) -> Int {
print("Food Array Count = \(self.foodArray.count)")
return self.foodArray.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: RESUABLE_VIEW, for: indexPath) as! CollectionReusableView
headerView.header.text = nameArray[indexPath.section]
return headerView
default:
assert(false, "Unexpected element kind")
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.width
let height = UIScreen.main.bounds.height/3
return CGSize(width: width, height: height)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ITEM_CELL, for: indexPath) as! MenuItemCollectionViewCell
cell.foodArray.removeAll()
cell.foodArray = self.foodArray[nameArray[indexPath.section]]!
print("Cell COol index = \(indexPath.section) , ARrray count = \(cell.foodArray.count)")
return cell
}
This is MenuItemCollectionViewCell and I set up FoodItemColletionView in this
import UIKit
import SDWebImage
class MenuItemCollectionViewCell: UICollectionViewCell ,UICollectionViewDelegate,UICollectionViewDataSource{
#IBOutlet weak var foodItemColletion: UICollectionView!
var foodArray :[Food] = []
var imageArray : [UIImage?] = []
let FOOD_ITEM_CELL : String = "FoodCell"
override func awakeFromNib() {
foodItemColletion.delegate = self
foodItemColletion.dataSource = self
super.awakeFromNib()
}
override func prepareForReuse() {
foodArray.removeAll()
super.prepareForReuse()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
for food in foodArray{
print("Title Menu item \(food.title)")
}
return foodArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FOOD_ITEM_CELL, for: indexPath) as! FoodItemCollectionViewCell
let foodObj = foodArray[indexPath.row]
cell.foodLabel.text = foodObj.title
cell.foodPrice.text = foodObj.price
cell.foodImage.sd_setImage(with: URL(string: "\(URLS.IMG_URL)\(foodObj.imageUrl)"), placeholderImage: nil, options: .refreshCached, progress: nil, completed: nil)
print("Title Menu Item Cell \(indexPath.item) = \(foodObj.title)")
return cell
}
}
This is FoodItemColletionViewCell
import UIKit
class FoodItemCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var foodImage: UIImageView!
#IBOutlet weak var foodLabel: UILabel!
#IBOutlet weak var foodPrice: UILabel!
#IBOutlet weak var cardView: CardView!
override func awakeFromNib() {
foodImage.layer.masksToBounds = true
foodImage.roundCorners(corners: [.topLeft,.topRight], radius: 5)
cardView.setElevation(points: 1.5)
layer.shouldRasterize = true
layer.rasterizationScale = UIScreen.main.scale
cardView.layer.cornerRadius = 5
}
override func prepareForReuse() {
super.prepareForReuse()
foodImage.image = nil
}
}
extension UIImageView{
func roundCorners(corners:UIRectCorner, radius: CGFloat) {
let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()
mask.path = path.cgPath
self.layer.mask = mask
}
}
This is top screen that is actually what I want
This is bottom screen that is actually want I want too
But when i scroll fast again from top to bottom, first cell moved to last cell and last cell moved to first cell.This is what happened what i want to fix
In MenuItemCollectionView change this method:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ITEM_CELL, for: indexPath) as! MenuItemCollectionViewCell
cell.foodArray.removeAll()
cell.foodArray = self.foodArray[nameArray[indexPath.section]]!
// add this, or else because of reusing the old data will be presented, even though you have set the new one
cell.foodItemColletion.reloadData()
print("Cell COol index = \(indexPath.section) , ARrray count = \(cell.foodArray.count)")
return cell
}

UICollctionView didSelectItemAt problems

I am trying to change an UIImage in the collectionviewcell with the help of on didSelectItemAt. It is working when I select cell on the beginning but when I scroll down and scroll back up the images are back to what they were and changed images shift to different cells.
First cell selected Image
Scrolled down then came up Image
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! RateCardCollectionViewCell
let tempString = "\(NSLocalizedString("base_url", comment: ""))\(itemImageLink[indexPath.row])"
let urlnew:String = tempString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
let url = URL(string: urlnew)
cell.rateCardImage.kf.setImage(with: url,placeholder: UIImage(named: "Junkart_Bin.png"))
cell.label.text = itemName[indexPath.row]
cell.itemRate.text = itemRate[indexPath.row]
cell.layer.cornerRadius = 3
cell.card.backgroundColor = UIColor.white
cell.card.layer.masksToBounds = false
cell.card.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
cell.card.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.card.layer.shadowOpacity = 1 //0.8
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! RateCardCollectionViewCell
if self.selectedRate == nil {
cell.changeImagetoSelected()
self.selectedRate = [Int]()
self.selectedRate.append(indexPath.row)
}
else {
}
}
Following is the UICollectionViewCell Class
class RateCardCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var rateCardImage: UIImageView!
#IBOutlet weak var card: UIView!
#IBOutlet weak var itemRate: UILabel!
#IBOutlet weak var selected_rate_image: UIImageView!
func changeImagetounSelected() {
selected_rate_image.image = UIImage(named: "unselected_rate")
}
func changeImagetoSelected() {
selected_rate_image.image = UIImage(named: "selected_rate")
}
}
Please Help!!
Check the cell creation index added on the selectedRate at the time of cell creation cellForItemAt.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! RateCardCollectionViewCell
// Your remaining codes are here.
if selectedRate.contains(IndexPath.row) {
cell.changeImageToSelected()
} else {
cell.changeImageTounselected()
}
return cell
}
This happened because collection view dequeue his cells. So you need to persist your selection in dataModel and get if cell is selected or no from it. So persist your selectedIndex in your viewController and in your cellForItemAt method call:
if(self.selectedIndex == indexPath.row){
cell.changeImageToSelected()
}
else{
cell.changeImageTounselected()
}
This will persist your selection when scroll

How can I add multiple collection views in a UIViewController in Swift?

I tried many days to realise this:
I want to add in my UIViewController two different CollectionView.
For example I want to put images in these collectionView
Each CollectionView use its own images.
Is this possible?
I will be very happy if somebody can give me a hand. :)
This is possible, you just need to add each UICollectionView as a subview, and set the delegate and dataSource to your UIViewController.
Here's a quick example. Assuming you have one UICollectionView working, you should be able to adapt this code to your own uses to add a second fairly easily:
let collectionViewA = UICollectionView()
let collectionViewB = UICollectionView()
let collectionViewAIdentifier = "CollectionViewACell"
let collectionViewBIdentifier = "CollectionViewBCell"
override func viewDidLoad() {
// Initialize the collection views, set the desired frames
collectionViewA.delegate = self
collectionViewB.delegate = self
collectionViewA.dataSource = self
collectionViewB.dataSource = self
self.view.addSubview(collectionViewA)
self.view.addSubview(collectionViewB)
}
In the cellForItemAtIndexPath delegate function:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewA {
let cellA = collectionView.dequeueReusableCellWithReuseIdentifier(collectionViewAIdentifier) as UICollectionViewCell
// Set up cell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCellWithReuseIdentifier(collectionViewBIdentifier) as UICollectionViewCell
// ...Set up cell
return cellB
}
}
In the numberOfItemsInSection function:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewA {
return 0 // Replace with count of your data for collectionViewA
}
return 0 // Replace with count of your data for collectionViewB
}
Yes--this is entirely possible. You can either assign their respective UICollectionViewDelegates/UICollectionViewDataSources to different classes or subclass the CollectionViews, assigning both the delegate and data source to your current viewController and downcast your reference to collectionView in the delegation methods like so:
#IBOutlet collectionViewA: CustomCollectionViewA!
#IBOutlet collectionViewB: CustomCollectionViewB!
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if let a = collectionView as? CustomCollectionViewA {
return a.dequeueReusableCellWithIdentifier("reuseIdentifierA", forIndexPath: indexPath)
} else {
return collectionView.dequeueReusableCellWithIdentifier("reuseIdentifierB", forIndexPath: indexPath)
}
}
Subclass UICollectionView like this:
class CustomCollectionViewA: UICollectionView {
// add more subclass code as needed
}
class CustomCollectionViewB: UICollectionView {
// add more subclass code as needed
}
You can use the factory design pattern to build two different collection views and return them via functions. Here's my working version for swift 4.
This code goes in a separate helper file:
import UIKit
class collectionViews {
static func collectionViewOne() -> UICollectionView {
let layout = UICollectionViewFlowLayout()
let collectionViewOne = UICollectionView(frame: CGRect(x: 0, y: 20, width: 200, height: 100), collectionViewLayout: layout)
return collectionViewOne
}
static func collectionViewTwo() -> UICollectionView {
let layout = UICollectionViewFlowLayout()
let collectionViewTwo = UICollectionView(frame: CGRect(x: 0, y: 300, width: 200, height: 100), collectionViewLayout: layout)
return collectionViewTwo
}
}
And here is the view controller code:
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
let collectionViewOne = collectionViews.collectionViewOne()
let collectionViewTwo = collectionViews.collectionViewTwo()
var myArray = ["1", "2"]
var myArray2 = ["3", "4"]
override func viewDidLoad() {
super.viewDidLoad()
collectionViewOne.delegate = self
collectionViewOne.dataSource = self
collectionViewOne.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
view.addSubview(collectionViewOne)
collectionViewTwo.delegate = self
collectionViewTwo.dataSource = self
collectionViewTwo.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell2")
view.addSubview(collectionViewTwo)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewOne {
return myArray.count
} else {
return myArray2.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewOne {
let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath as IndexPath)
myCell.backgroundColor = UIColor.red
return myCell
} else {
let myCell2 = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell2", for: indexPath as IndexPath)
myCell2.backgroundColor = UIColor.blue
return myCell2
}
}
}
Result
You can also name the collection views outlets differently (without subclassing):
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var SecondCollectioView: UICollectionView!
method:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) as UICollectionViewCell
if(collectionView == self.SecondCollectioView) {
cell.backgroundColor = UIColor.black
} else {
cell.backgroundColor = self.randomColor()
}
return cell;
}
This is will be an another way.
Here's my working version for swift 5 and Xcode 11:
create outlets for corresponding collectionviews: outlets:
#IBOutlet weak var bgCollectionView: UICollectionView!
#IBOutlet weak var frontCollectionView: UICollectionView!
var arrImages = [String : [UIImage]]()
arrImages is contain like
override func viewDidLoad() {
super.viewDidLoad()
arrImages = [
"frontImg": [//Front UIImage array],
"bgImg": [//Background UIImage array]
]
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let arrImg = arrImages["bgImg"] {
return arrImg.count
} else if let arrImg = arrImages["frontImg"]{
return arrImg.count
}
return 0
}
You can do this two ways
Using CollectionView Outlets
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
if collectionView == self.bgCollectionView{
if let arrImg = arrImages["bgImg"]{
cell.imgView.image = arrImg[indexPath.row]
}
}else{
if let arrImg = arrImages["frontImg"]{
cell.imgView.image = arrImg[indexPath.row]
}
}
return cell
}
Using CollectionView Tag:
Here Background Images collectionview tag is 1 and Front Images collectionview tag is 2.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
if collectionView == collectionView.viewWithTag(1){
if let arrImg = arrImages["bgImg"]{
cell.imgView.image = arrImg[indexPath.row]
}
}else{
if let arrImg = arrImages["frontImg"]{
cell.imgView.image = arrImg[indexPath.row]
}
}
return cell
}
Please Add Tag in CollectionView Like this:
Thank You. Hope It's working for you !!
Swift 5 Answer!
If you try connecting both collectionViews to the same view controller Xcode will throw an error "Outlets cannot connect to repeating content"
Solution:
Head to Storyboard
Connect the first collectionView via outlet, set the delegate/dataSource in viewDidLoad and then add a tag to the second collectionView by heading to the attributes inspector in storyboard and change the value from 0 to 1
Select the secondCollectionView and go to the connections inspector and select delegate and drag the connection to the UIViewController and the same for the dataSource.
Simply check which collectionView is passing through.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == collectionView.viewWithTag(1) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "secondCollectionView", for: indexPath)
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "firstCollectionView", for: indexPath) as! HomeMainCollectionViewCell
cell.configureCell()
return cell}
}

Resources