I have a tableView in which I have 2 custom cells, in both cells I have different CollectionView, the dataSource and delegate of both the CollectionViews is my ViewController.
So now how do I check which CollectionViews is to be configured in UICollectionView's respective methods?
Here is the view hierarchy
How do I come to know which is the collectionView that's there in the parameter of above function?
So here is my code:
class FeatureBannerTableViewCell: UITableViewCell {
#IBOutlet weak var featureCollectionView: UICollectionView!
}
class FeaturedTableViewCell: UITableViewCell {
#IBOutlet weak var FeatureTitle: UILabel!
#IBOutlet weak var seeAllButton: UIButton!
#IBOutlet weak var collectionView: UICollectionView!
}
extension ViewController: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 2,3,6,7:
let cell = featuredTableView.dequeueReusableCellWithIdentifier("FeatureBannerTableViewCell", forIndexPath: indexPath) as! FeatureBannerTableViewCell
cell.featureCollectionView.dataSource = self
cell.featureCollectionView.delegate = self
return cell
default:
let cell = featuredTableView.dequeueReusableCellWithIdentifier("FeaturedTableViewCell", forIndexPath: indexPath) as! FeaturedTableViewCell
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
return cell
}
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// how do I know if this collectionView is collectionView or featureCollectionView?
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// how do I know if this collectionView is collectionView or featureCollectionView?
}
}
I would use the tag property in UIView to identify your collection view. So when you configure your table cells in cellForRowAtIndexPath get the collection view of the cell and set its tag to something unique (I would use the row value of indexpath).
extension ViewController: UITableViewDataSource {
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 2,3,6,7:
let cell = featuredTableView.dequeueReusableCellWithIdentifier("FeatureBannerTableViewCell", forIndexPath: indexPath) as! FeatureBannerTableViewCell
cell.featureCollectionView.dataSource = self
cell.featureCollectionView.delegate = self
cell.featureCollectionView.tag = indexPath.row
return cell
default:
let cell = featuredTableView.dequeueReusableCellWithIdentifier("FeaturedTableViewCell", forIndexPath: indexPath) as! FeaturedTableViewCell
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
cell.collectionView.tag = indexPath.row
return cell
}
}
}
Then in your collection view methods get the tag value and that will tell you which one of the many collection views it is.
extension ViewController: UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// how do I know if this collectionView is collectionView or featureCollectionView?
let datasourceIndex = collectionView.tag
// now use your datasource for the following index
}
}
I think, you can make use of isKindOfClass
Example:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyReuseIdentifier", for: indexPath as IndexPath) as! UICollectionViewCell
if cell.isKindOfClass(FeaturedBannerCollectionCell){
//implementation code
} else cell.isKindOfClass(FeaturedCollectionViewCell) {
//implementation code
}
return cell
}
Related
I inserted Label into CollectionView cell but when I made outlet this error appeared.
error: The currencyLabel outlet from the ViewController to the UILabel is invalid. Outlets cannot be connected to repeating content
class ViewController: UIViewController {
var currency = Currency.getCurrency()
#IBOutlet var currencyLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return currency.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "currencyCell", for: indexPath) as! CurrencyCollectionViewCell
let currencyList = currency[indexPath.row]
currencyLabel.text = "\(currencyList.currency) \n \(currencyList.cash)"
return cell
}
}
You need to create IBOutlet of your currencyLabel in CurrencyCollectionViewCell class, and use it like
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "currencyCell", for: indexPath) as! CurrencyCollectionViewCell
let currencyList = currency[indexPath.row]
cell.currencyLabel.text = "\(currencyList.currency) \n \(currencyList.cash)"
return cell
}
You have made a simple mistake.
You should make below outlet in CollectionViewCell not in your ViewController.
#IBOutlet var currencyLabel: UILabel!
I'm looking for your help for my association between a tableview and a collection view.
I've got a CollectionView with 6 horizontal scrollable cells.
In each cell, I would like to put a table view.
For each tableView, I need to know in which cell I am to put my wanted data.
Actually, I make my code work for displaying tableView inside the cells but I'm blocked for finding in which collection view cell I am.
BTW, my Meal_vc_cell controller is actually Empty, it just has a simple outlet. Nothing else.
Here is my code
class TrainFoodPlanViewController: BaseViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UITableViewDataSource, UITableViewDelegate {
let train_meals_list: [String] = ["breakfast", "snack_1", "pre_intra_post", "lunch", "snack_2", "diner"]
#IBOutlet weak var trainCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Food Plan"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return train_meals_list.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! Meal_vc_cell
cell.meal_number.text = train_meals_list[indexPath.row]
return cell
}
}
Here is what I'm trying to do
There are a number of ways this can be achieved. My recommendation is to subclass UITableView and add a parentCollectionViewIndexPath property
class MyCustomTableView: UITableView {
var parentCollectionViewIndexPath: IndexPath?
}
I'm assuming Meal_vc_cell has an outlet to the relevant tableView. Change that tableView's type to MyCustomTableView
class Meal_vc_cell: UITableViewCell {
#IBOutlet weak var tableView: MyCustomTableView
}
Note: If you're using storyboard, don't forget to update the tableView's class in storyboard as well
Now, just set parentCollectionViewIndexPath in the collectionView's cellForItemAt method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! Meal_vc_cell
cell.tableView.parentCollectionViewIndexPath = indexPath
return cell
}
My ViewController consists of a UIButton and a UICollectionView which has 4 cells. I will select any cell and when I tap the button I want to get the data from only the selected UICollectionViewCell.
The UIButton is outside the UICollectionView and UICollectionViewCell.
You can use indexPathsForSelectedItems to get the indexPaths for all selected Items. After you requested all the IndexPath you can simply ask the collectionView for the corresponding cell to get your Data.
import UIKit
class TestCell: UICollectionViewCell {
var data : String?
}
class ViewController: UIViewController {
var model = [["1","2","3","4"]]
#IBOutlet weak var collectionView: UICollectionView?
#IBAction func buttonTapped(sender: AnyObject) {
if let collectionView = self.collectionView,
let indexPath = collectionView.indexPathsForSelectedItems?.first,
let cell = collectionView.cellForItem(at: indexPath) as? TestCell,
let data = cell.data {
print(data)
}
}
}
extension ViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return model.count
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return model[section].count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("test", forIndexPath: indexPath) as! TestCell
cell.data = self.model[indexPath.section][indexPath.row]
return cell
}
}
I have a UICollectionView with a custom cell with an UIImageView in it as well as a custom class with the outlet
class theCell: UICollectionViewCell {
#IBOutlet var theImage:UIImageView!
}
I have an array of UIImage (Which only has one constant image). The image is in the main bundle.
var tempImages = [UIImage(named: "placeholder.png" )]
delegate methods
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tempImages.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = self.collectionView?.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! theCell
//Unexpectadly found nil
cell.theImage.image = tempImages[indexPath.row]
return cell
}
If you have added this line:
self.collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "cell")
then remove this first and here is complete working code:
CollectionViewController.swift
import UIKit
class CollectionViewController: UICollectionViewController {
var tempImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
tempImages.append(UIImage(named: "bg.jpg")!)
}
// MARK: UICollectionViewDataSource
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
//#warning Incomplete method implementation -- Return the number of sections
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//#warning Incomplete method implementation -- Return the number of items in the section
return tempImages.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CollectionViewCell
// Configure the cell
cell.theImage.image = tempImages[indexPath.row]
println(cell.theImage.image)
return cell
}
}
CollectionViewCell.swift
import UIKit
class CollectionViewCell: UICollectionViewCell {
#IBOutlet var theImage:UIImageView!
}
And don't forget to assign Identifier to your cell:
Sample for more Info.
Try registering first in cellForItemAtIndexPath:
collectionView.registerNib(UINib(nibName: "FeedCell", bundle: nil), forCellWithReuseIdentifier: "cell")
EDIT
In your situation:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
collectionView.registerNib(UINib(nibName: "FeedCell", bundle: nil), forCellWithReuseIdentifier: "cell")
let cell = self.collectionView?.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! theCell
cell.theImage.image = tempImages[indexPath.row]
return cell
}
The problem is reinitialize tempImages array so it return nil.
var tempImages = [UIImage(named: "placeholder.png" )]
import UIKit
let reuseIdentifier = "MyCell"
class ViewController: UIViewController, UICollectionViewDataSource {
var myimage = UIImage(named: "1433584709_clock_ios7_ios_7")
#IBOutlet weak var collectionView: UICollectionView!
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.imageView.image = myimage
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.collectionViewLayout = CollectionViewLayout()
self.collectionView.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
// Do any additional setup after loading the view, typically from a nib.
}
}
I have this code to add so many cells with same image.
However, I want to make cells to have different pictures.
Please tell me how to do this.
Use array of images instead of var myImage because collection view or tableview need some form of list or array to store all items. The indexPath.row will return the index of the images the collectionview is looking for. i.e.
var images: [String] = ["image1", "image2"]
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.imageView.image = UIImage(named: self.images[indexPath.row])
return cell
}
Also in function collectionView:numberOfItemsInSection:
return self.images.count
Here is the complete code assuming you have a custom CollectionViewCell class
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
var images : [String] = ["image1", "image2"]
private let reuseIdentifier = "MyCell"
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell
cell.imageView.image = UIImage(named: self.images[indexPath.row])
return cell
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.images.count
}
}
Where are your images coming from?
Suppose I have a 2D array of images like myImageArray[][], then change line:
cell.imageView.image = myImage
to
cell.imageView.image = myImageArray[indexPath.section][indexPath.row]