collection view arrays tied to index - ios

Im making a three view controller project with the first two views are collectionViews. The selected cell will load second view controller with segue and another array depending on which index was selected on first main view. Can anyone point me in the right direction on how to tie a data to load in the second collection view.
import UIKit
class ViewController: UIViewController {
#IBOutlet private weak var collectionView: UICollectionView!
var collectionData = ["cell1", "cell2", "cell3", "cell4", "cell5", "cell6", "cell7", "cell8"]
override func viewDidLoad() {
super.viewDidLoad()
let height = (view.frame.size.width / 2.76)
let width = view.frame.size.width / 1
let layout = collectionView.collectionViewLayout as!
UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return collectionData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath)
if let label = cell.viewWithTag(100) as? UILabel {
label.text = collectionData[indexPath.row]
}
return cell
}
didSelectItemAt indexPath: IndexPath) {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "BannerSegue" {
if let _ = segue.destination as? BannerSelection, let _ = sender as? IndexPath {
}
}
}
}
that is the main view controller. then it has a segue to this view
import UIKit
class BannerSelection: UIViewController {
#IBOutlet weak var collection2: UICollectionView!
var BannerData = ["bannerA1", "bannerA2", "bannerA3", "bannerA4", "bannerA5", "bannerA6", "bannerA7", "bannerA8", "bannerA9", "bannerA10", "bannerA11", "bannerA12"]
var selection: String!
override func viewDidLoad() {
super.viewDidLoad()
let height = (view.frame.size.width / 3.76)
let width = view.frame.size.width / 1
let layout = collection2.collectionViewLayout as!
UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
}
extension BannerSelection: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return BannerData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let bannercell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerSelectionCell", for: indexPath)
if let label = bannercell.viewWithTag(1) as? UILabel {
label.text = BannerData[indexPath.row]
}
return bannercell
}
func collectionView(_ BannerSelection: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
So what im trying to achieve is let's say... index 2 to have an array of "bannerB1, bannerB2" so on and so forth. then i will apply the same technique for the second view controller to populate the final view with a end UIImage. Thank you in advanced!

You can store the data of the first view in the UserDefaults and then retrieve the first vc's data from the second view and load them

As your data Structure is unclear to me, Seems like your data is a dictionary of array like that
dict = [
"cell1" : [Banner1, Banner2,..]
"cell2" : [Apple1, Apple2, ..]
//so on
]
What is the structure of your data structure, let it to be saved in UserDefaults.
UserDefaults.standard.setValue(dict, forKey: "myDataStructure")
while retrieve in second view controller
let array = dict["cell1"] as? Array<String> // depends on the data structure
and populate your viewController.

Related

How can I dynamically set multiple buttons having different length of string according to screen's width?

(source: uimovement.com)
I want to implement layout like the above(auto line break when screen's width is not enough to accommodate buttons' widths).
But I can't come up with any idea about how to make that image like layout. I just can implement statically, not dynamically.
In Android, there is a layout that can implement the above.
But I don't know what can help me implement the above image in swift.
Please help me.
Following #Matthew Mitchell 's suggestion.
I implemented it like below.
My ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var hobbyArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
// self.collectionView!.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cell")
hobbyArray.append("test1")
hobbyArray.append("test2")
hobbyArray.append("test3")
hobbyArray.append("test4")
hobbyArray.append("test5")
hobbyArray.append("test5")
hobbyArray.append("test5123123")
collectionView.reloadData()
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return hobbyArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.title.text = self.hobbyArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = self.hobbyArray[indexPath.row]
let cellWidth = text.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
return CGSize(width: cellWidth, height: 35.0)
}
}
Other codes are implemented exactly equal to #Matthew Mitchell's codes.
However, still I can't get what I wanted to implement.
I failed to make what I had wanted.
To do this efficiently you need to have a UICollectionView with a custom FlowLayout. I am going to do a storyboard example. This is quite complicated so I will try my best. All the code will be below the steps.
Step 1: Create a swift file named CollectionViewFlowLayout and use UICollectionViewLayout code in the newly created class.
Step 2: Add a UICollectionView to your ViewController
Step 3: Link new UICollectionView layout with the CollectionViewFlowLayout class
Step 4: Create a UICollectionViewCell inside the UICollectionView, add a label to that cell and constrain it to left and right in the cell and center it vertically. In the attributes inspector of the cell give it a reusable identifier ("cell" for this example)
Step 6: Create a swift file named collectionViewCell and use UICollectionViewCell class that links to your collectionViewCell (same way you linked your flowlayout in step 3).
Step 7: Add ViewController code to your ViewController Class. This code allows you to add cells to your collection view. The sizeForItemAt function will allow you to resize the cells according to the width of the string that you put inside each cell.
Code:
ViewController:
import UIKit
class viewController: UIViewController {
//Outlets
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return YOUR_ITEM_COUNT
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
self.title.text = YOUR_ITEMS_LIST[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let text = YOUR_ITEMS_LIST[indexPath.row]
let cellWidth = text!.size(withAttributes:[.font: UIFont.systemFont(ofSize:17)]).width + 25
return CGSize(width: cellWidth, height: 35.0)
}
}
UICollectionViewCell:
class CollectionViewCell: UICollectionViewCell {
//Outlets
#IBOutlet weak var title: UILabel!
}
UICollectionViewFlowLayout:
import UIKit
class CollectionViewFlowLayout: UICollectionViewFlowLayout {
var tempCellAttributesArray = [UICollectionViewLayoutAttributes]()
let leftEdgeInset: CGFloat = 0
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let cellAttributesArray = super.layoutAttributesForElements(in: rect)
//Oth position cellAttr is InConvience Emoji Cell, from 1st onwards info cells are there, thats why we start count from 2nd position.
if(cellAttributesArray != nil && cellAttributesArray!.count > 1) {
for i in 1..<(cellAttributesArray!.count) {
let prevLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i - 1]
let currentLayoutAttributes: UICollectionViewLayoutAttributes = cellAttributesArray![i]
let maximumSpacing: CGFloat = 8
let prevCellMaxX: CGFloat = prevLayoutAttributes.frame.maxX
//UIEdgeInset 30 from left
let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
let currentCellExpectedMaxX = prevCellMaxX + maximumSpacing + (currentLayoutAttributes.frame.size.width )
if currentCellExpectedMaxX < collectionViewSectionWidth {
var frame: CGRect? = currentLayoutAttributes.frame
frame?.origin.x = prevCellMaxX + maximumSpacing
frame?.origin.y = prevLayoutAttributes.frame.origin.y
currentLayoutAttributes.frame = frame ?? CGRect.zero
} else {
// self.shiftCellsToCenter()
currentLayoutAttributes.frame.origin.x = leftEdgeInset
//To Avoid InConvience Emoji Cell
if (prevLayoutAttributes.frame.origin.x != 0) {
currentLayoutAttributes.frame.origin.y = prevLayoutAttributes.frame.origin.y + prevLayoutAttributes.frame.size.height + 08
}
}
}
}
return cellAttributesArray
}
func shiftCellsToCenter() {
if (tempCellAttributesArray.count == 0) {return}
let lastCellLayoutAttributes = self.tempCellAttributesArray[self.tempCellAttributesArray.count-1]
let lastCellMaxX: CGFloat = lastCellLayoutAttributes.frame.maxX
let collectionViewSectionWidth = self.collectionViewContentSize.width - leftEdgeInset
let xAxisDifference = collectionViewSectionWidth - lastCellMaxX
if xAxisDifference > 0 {
for each in self.tempCellAttributesArray{
each.frame.origin.x += xAxisDifference/2
}
}
}
}
You can use a UICollectionView with custom UICollectionViewFlowLayout or use a fully custom solution with UIView as root and different UIScrollViews with some custom content as lines (cells) here.
I have an example, but it's too huge to post here. Write me if you are inserting in.
I had the same problem and i found a shortest and super easy solution to make the height dynamic by subclassing UICollectionView and assign it to the CollectionView.
Here's the code:
class DynamicHeightCollectionView: UICollectionView {
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
return self.collectionViewLayout.collectionViewContentSize
}
}
I am attaching reference link to that solution.
https://stackoverflow.com/a/49297382/9738186

How to open activity and pass variable on selection of collectionview cell?

I have a collectionView and I am using a custom cell that shows an Image and label. I am populating the view with an array. When a cell is selected, I want a new activity to open and the name of the class to be passed through.
Here is my code:
class CollectionViewController: UICollectionViewController {
let classes = ["English","Math","Science","Social Studies","Other","Technology"]
let class_images : [UIImage] = [
UIImage(named: "English")!,
UIImage(named: "Math")!,
UIImage(named: "Science")!,
UIImage(named: "Social Studies")!,
UIImage(named: "Other")!,
UIImage(named: "Technology")!
]
override func viewDidLoad() {
super.viewDidLoad()
var layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 22, left: 22, bottom: 22, right: 22)
layout.minimumInteritemSpacing = 22
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return classes.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "class_cell", for: indexPath) as! custom_class_cell
cell.class_name.text = classes[indexPath.item]
cell.class_image.image = class_images[indexPath.item]
// Configure the cell
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.black.cgColor
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//This isn't the right code, but an example of what I want to do!
if (indexPath=1){
let vc = self.storyboard?.instantiateViewController(withIdentifier:
"classes")
self.present(vc!, animated: true, completion: nil)
//I want to pass this string to the class
let class_name2 = "English"
}
else if(indexPath=2){
let vc = self.storyboard?.instantiateViewController(withIdentifier:
"classes")
self.present(vc!, animated: true, completion: nil)
//I want to pass this string to the class
let class_name2 = "Math"
//it keeps going through the technology cell
}
}
In the didSelectItemAt method, there is an example of what I am trying to do, but the code isn't right. I want to do this for all cells English to Technology. Thank you in advance and let me know if you have any questions!
easiest way:
in dest controller (let's say is a DetailController instance)
you should have:
class DetailController...
... var myInfo : MyInfo?
(MyInfo should contain ALL data You want to pass.)
and in prepare for segue:
vc.myInfo = Info(class_name2)
in viewDidLoad populate your UI:
override func viewDidLoad() {
super.viewDidLoad()
self.detail.text = self. myInfo....
It is actually a really simple solution, I just over complicated it!
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let valueToPass = classes[indexPath.row]
That gets you name of each class when the cell is clicked. After that, just do the prepare for segue method.

Get indexPath from UICollectionViewController to UICollectionViewCell subclass

in my view controller I Am loading a custom CollectionViewCell with subclass. Based on the position of a cell's indexpath I want to format the text labels differently. I.e. first row has only one cell with bigger text, whereas the second has two cell with smaller text.
How can I access the indexpath from my UICollectionView in my UICollectionViewCell subclass? I tried a delegate protocol but this always returns nil.
Code below and Thanks so much!
Markus
UICollectionViewController:
import UIKit
protocol WorkoutDataViewControllerCVDataSource: AnyObject {
func workoutType(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> WorkoutType
func workoutDistance(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutDuration(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
func workoutInstantVelocity(for workoutDataViewControllerCV: WorkoutDataViewControllerCV) -> Double
}
final class WorkoutDataViewControllerCV: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
weak var dataSource: WorkoutDataViewControllerCVDataSource!
private lazy var velocityFormatter = VelocityFormatter(dataSource: self, delegate: self)
private lazy var averageVelocityFormatter = VelocityFormatter(dataSource: self, delegate: self)
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.register(MeasurementCollectionViewCell.preferredNib, forCellWithReuseIdentifier: MeasurementCollectionViewCell.preferredReuseIdentifier)
}
}
// MARK: - Managing UICollectionView
extension WorkoutDataViewControllerCV: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Measurement Cell", for: indexPath)
return cell
}
}
extension WorkoutDataViewControllerCV: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let availableWidth = self.view.frame.width
switch indexPath.row {
case 0: return CGSize(width: availableWidth, height: 150)
case 1: return CGSize(width: availableWidth/2.1, height: 150)
case 2: return CGSize(width: availableWidth/2.1, height: 150)
case 3: return CGSize(width: availableWidth, height: 150)
default:
return CGSize(width: availableWidth/2.1, height: 150)
}
}
}
// MARK: - Managing VelocityFormatter
extension WorkoutDataViewControllerCV: VelocityFormatterDataSource {
func duration(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutDuration(for: self)
}
func distance(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutDistance(for: self)
}
func instantVelocity(for velocityFormatter: VelocityFormatter) -> Double {
return dataSource.workoutInstantVelocity(for: self)
}
}
UICollectionViewCell.swift
import UIKit
final class MeasurementCollectionViewCell: UICollectionViewCell {
#IBOutlet private var measurementPropertyLabel: UILabel!
#IBOutlet private var measurementValueLabel: UILabel!
#IBOutlet private var measurementUnitLabel: UILabel!
static let preferredReuseIdentifier = "Measurement Cell"
static let preferredNib = UINib(nibName: "MeasurementCollectionViewCell", bundle: nil)
override func awakeFromNib() {
super.awakeFromNib()
updateMeasurement(property: "Speed", value: "100", unit: "km/h")
//measurementValueLabel.font = measurementValueLabel.font.monospacedDigitFont
}
func updateMeasurement(property: String, value: String, unit: String?) {
measurementPropertyLabel.text = property
measurementValueLabel.text = value
measurementUnitLabel.text = unit
}
}
Get the instance of cell in UICollectionView delegate method collectionView(_, didSelectItemAt _).
extension WorkoutDataViewControllerCV: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? MeasurementCollectionViewCell {
cell.selectedIndexPath(indexPath)
}
}
}
The indexPath will be passed as an argument in method selectedIndexPath to MeasurementCollectionViewCell from above method.
class MeasurementCollectionViewCell: UICollectionViewCell {
......
func selectedIndexPath(_ indexPath: IndexPath) {
//Do your business here.
}
}
You can use the responder chain to get the collection view of a cell with which you can get the index path. Just add these extensions in a new file called UICollectionViewCell+IndexPath.swift.
extension UIResponder {
func next<T: UIResponder>(_ type: T.Type) -> T? {
return next as? T ?? next?.next(type)
}
}
extension UICollectionViewCell {
var indexPath: IndexPath? {
return next(UICollectionView.self)?.indexPath(for: self)
}
}
Now inside your cell, you can use self.indexPath
Pretty straight forward way would be storing the indexPath into the subclass of UICollectionViewCell class. Assign it while returning from cellForRow at: index path. So now the subclassed collectionviewcell has access to the indexpath of it's own

How can I put 2 collectionViews in a single ViewController?

I have this code to make a UICollectionView with in another ViewController:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tvSeries.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier = "Item"
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! SeriesCollectionViewCell
cell.itemLabel.text = tvSeries[indexPath.row]
cell.itemImage.image = UIImage.init(imageLiteralResourceName: tvSeries[indexPath.row])
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let item = sender as? UICollectionViewCell
let indexPath = collectionView.indexPath(for: item!)
let detailVC = segue.destination as! DetailViewController
detailVC.detailName = tvSeries[(indexPath?.row)!]
}
I want to have a ViewController with 2 CollectionViews like in this picture:
In your collectionView functions such as numberOfItemsInSection, check if the collectionView argument is equal to one or the other collection view and then return the number as required.
For example, if you had the following IBOutlets:
#IBOutlet weak var collectionViewOne: UICollectionView!
#IBOutlet weak var collectionViewTwo: UICollectionView!
then your numberOfItemsInSection would change to:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == collectionViewOne {
return itemSource1.count
}
else {
return itemSource2.count
}
}
Do the same for the rest of the collectionView functions.

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