Collection view cell doesn't recognize its outlet - ios

I have a collection view controller ItemCollectionVC, I want to populate its cells with images, this is how I set it:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
cell.cellImage.image = dataSourceItems[indexPath.row].image
// Error
return cell
}
Hoever, there's an error: Value of type UICollectionViewCell have no
member cellImage
The cell is of custom cell ItemCell, I set its custom class in story board, and here is ItemCell:
class ItemCell: UICollectionViewCell {
#IBOutlet weak var cellImage: UIImageView!
}
I also connected the outlet to the image view of the cell.
So I don't understand why there's an error, anybody knows?

Just one mistake that you need to define class for cell as! ItemCell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! ItemCell

Related

Add title to CollectionViewCell

I have a collection view inside a table view. What I want to do next is to set a title to each of the cells inside the collection view.
I have this code inside the ViewController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.titleLabel.text = "123"
return cell;
}
This is the cell class
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var titleLabel: UILabel!
}
When I try to add a label inside the cell and then use this label to set the title to it nothing is displayed inside the cell.
This is my current stack:
What am I doing wrong here?

UICollecionView inside UITableView. How to handle selections?

I am making a form with a tableView with multiple kind of cell types. One of these types contains an UICollectionView with buttons to select some answers.
What I need is to be able to hide or show rows in the table, regarding on the answers.
For example: when answer to question 2 is "No", question 3 is not showing anymore.
But I don't know how to make that tableview knows what's being selected in one of it's cells
In the cell that contains the UICollectionView I have this method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let indexPath = optionsCollectionView.indexPathsForSelectedItems?.first
let cell = collectionView.cellForItem(at: indexPath!) as! OptionsCollectionViewCell
let data = cell.itemButton.titleLabel?.text
selectedItem = data
}
But I don't know how to automatically pass it to the tableview so it knows what rows to show or hide... Any idea?
this is my cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if sortedFixedContentType.count != 0 {
let item = sortedFixedContentType[indexPath.row]
switch item.typeId {
case "42":
let cell = tableView.dequeueReusableCell(withIdentifier: "FormFileCell", for: indexPath) as! FormFileCell
return cell;
case "39":
let cell = tableView.dequeueReusableCell(withIdentifier: "FormExpenseTypeCell", for: indexPath) as! FormExpenseTypeCell
return cell;
case "86":
let cell = tableView.dequeueReusableCell(withIdentifier: "FormExpensePaymentModeCell", for: indexPath) as! FormExpensePaymentModeCell
return cell;
case "87":
let cell = tableView.dequeueReusableCell(withIdentifier: "FormExpenseFileTypeCell", for: indexPath) as! FormExpenseFileTypeCell
return cell;
case "88":
let cell = tableView.dequeueReusableCell(withIdentifier: "FormProviderCell", for: indexPath) as! FormProviderCell
return cell;
default:
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! BaseFormCell
cell.idLabel.text = item.htmlType
return cell
}
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! BaseFormCell
cell.idLabel.text = ""
return cell
}
}
Thanks
There are Four steps to do this :-
1.First create a protocol lets say 'CustomCellDelegate' in your custom cell where you are using collectionview inside and create a variable that will hold the custom delegate just to give a example suppose your cell name is CustomCell create a CustomCellDelegate and declare it as customDelegate
protocol CustomCellDelegate : class {
func Method1()
}
class CustomCell : UITableViewCell {
var customDelegate : CustomCellDelegate?
}
2.Then you need to fire that delegate from CustomCell class collectionview delegate method didSelectItemAt like this
extension CustomCell : UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let delegate = customDelegate {
delegate.Method1()
}
}
}
3.Third assign the customDelegate to the view controller where you want to get the delegate for example myViewController here
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customeCellIdentifier", for: indexPath) as! CustomCell
cell.customDelegate = self // myViewController
return cell
}
4.Handle the delegate in your view controller like this
extension myViewController : CustomCellDelegate {
func Method1() {
print("Method 1 called")
}
}
I Hope this will solve your problem let me know if you find this answer helpful. Cheers!!

Implement didSelect in a collection view inside a cell

I am trying to perform a segue from a collection view which is inside a table view cell, the view looks like this
enter image description here
To explain it well, I have a table view, each row has a cell , inside the second row , I have a collection view which includes several products
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemTitle", for: indexPath)
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "SectionTitle", for: indexPath)
return cell
case 4:
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
}
}
Inside my ItemCell class I have the following
#IBOutlet weak var collectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "singleItemCell", for: indexPath) as! singleItemCell
cell.itemImage.image = images[indexPath.row]
cell.itemImage.contentMode = .scaleAspectFit
return cell
}
I want to perform a segue such as when the user select a cell from the collection view, It takes him to another view controller. How can I do that ?
I tried performSegue but it does not allow me since I am in the cell class
Please any tips ?
In Your ItemCell class make a variable for referencing your ViewController like this:
var productVC:UIVIewController?
while loading TableView Cell set the reference to self like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath)
cell.productVC = self
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
}
}
then implement the didSelect UICollectionView delegate method in ItemCell Class
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
productVC.performSegue(withIdentifier: "pass your segue identifier here..", sender: nil)
}
protocol ProductCellDelegate: class {
func didChoosedProduct(item: ItemImage)
}
class ProductCell {
#IBOutlet weak var collectionView: UICollectionView!
// Your Model Array
var itemImages: [ItemImages] = [] {
didSet {
self.collectionView.reloadData()
}
// Must set the delegate to your viewcontroller object in tableviewcell cell for rowat indexpath method
weak var delegate: ProductCellDelegate?
override func awakeFromNib() {
self.collectionView.delegate = self
}
}
extension ProductCell: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedItem = self.itemImages[indexPath.row]
self.delegate?.didChoosedProduct(item: selectedItem)
}
}
Implement ProductCellDelegate in your viewcontroller. Call performsegue to navigation.
Implement UICollectionViewDataSource and UICollectionViewDelegate not in tableView cell, but in your ViewController.
You can access to collectionView in cellForRowAtIndexPath method, so you can assign it dataSource and delegate to self
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath)
return cell
case 1:
if let cell = tableView.dequeueReusableCell(withIdentifier: "ItemTitle", for: indexPath) as? ItemCell {
cell.collectionView?.delegate = self
cell.collectionView?.dataSource = self
return cell
}
...
}
}
And from ViewController you can make performSegue method

Register nib with collectionview

I have FeedCell.swift and FeedCell.xib, in feedcell xib i set cell custom class to 'FeedCell'
Code in view controller viewDidLoad
collectionView.register(UINib(nibName: "FeedCell", bundle: .main), forCellWithReuseIdentifier: "feedCell")
Problem:
I want to subclass FeedCell and use that class with collectionView
Like:
class FeedCell:UICollectionViewCell {
#IBOutlet weak var showImageView: UIImageView!
#IBOutlet weak var showIconImageView: UIImageView!
}
class AppFeedCell: FeedCell {
override func awakeFromNib() {
super.awakeFromNib()
// configure cell
}
}
How to register/use FeedCell and AppFeedCell with collectionview?
If your AppFeedCell have a different UI Configuration, for example it does not bind some IBOutlets defined in FeedCell or it adds new ones not present in it's superclass, then you will have to register both Nibs (asuming you have two separated Nib files)
collectionView.register(UINib(nibName: "FeedCell", bundle: .main), forCellWithReuseIdentifier: "feedCell")
collectionView.register(UINib(nibName: "AppFeedCell", bundle: .main), forCellWithReuseIdentifier: "appFeedCell")
And then you will be able to dequeue each one when you need.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if you_need_AppFeedCell {
let cell : AppFeedCell = collectionView.dequeueReusableCellWithReuseIdentifier("appFeedCell", forIndexPath: indexPath) as! AppFeedCell
return cell
} else
let cell : FeedCell = collectionView.dequeueReusableCellWithReuseIdentifier("feedCell", forIndexPath: indexPath) as! FeedCell
return cell
}
}
This way you may have two different Nib files even if AppFeedCell subclass FeedCell.
Otherwise, if both class and subclass share the same cell layout and outlets, then simply by casting the dequeued cell (FeedCell) to AppFeedCell should be enough, without registering another Nib, as Taras Chernyshenko pointed above.
You don't need to register separate xib for AppFeedCell. You already registered nib to your collectionView.
Just dequeue cell and cast it to needed class in your cellForItemAtIndexPath.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath
indexPath: NSIndexPath) -> UICollectionViewCell {
if you_need_AppFeedCell {
let cell : AppFeedCell = collectionView.dequeueReusableCellWithReuseIdentifier("feedCell", forIndexPath: indexPath) as! AppFeedCell
return cell
} else
let cell : FeedCell = collectionView.dequeueReusableCellWithReuseIdentifier("feedCell", forIndexPath: indexPath) as! FeedCell
return cell
}
}
Your AppFeedCell will inherit all outlets from FeedCell so it should work as well.
In your cell xib/storyboard go to Identity inspector set class: AppFeedCell
Now in Datasource Methods of collectionview you can create cell of type AppFeedCell.
Try this.
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : AppFeedCell = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! AppFeedCell
return cell
}

how to use custom cell in collection view controller in swift 3

I am using swift 3 - I know how to show some Images in collection view with custom Cell - the problem is that I can't use custom cell in Collection View Controller
here is the collection view Controller Codes
private let reuseIdentifier = "uploadCell"
class uploadedFiles: UICollectionViewController {
var images = ["1.jpg" , "2.jpg" , "3.jpg" , "4.jpg" ]
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
//myCollectionView.sizeToFit()
//cell.sizeToFit()
cell.cellImages.image = UIImage(named: images[indexPath.row])
return cell
}
and here is the Collection view Cell Code
import UIKit
class UICollectionViewCell: UICollectionViewCell {
#IBOutlet weak var cellImages: UIImageView!
}
remember that I used "uploadCell" for identifier
For using CollectionView Custom Cell
Step 1: Create Subclass of CollectionViewCell
class ImageCell: UICollectionViewCell {
#IBOutlet weak var imgView: UIImageView!
}
Step 2: set CollectionViewCell class in StoryBoard
Step 3: reuseCollectionView Cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCell", for: indexPath) as! ImageCell
cell.imgView.image = self.arrMedia[indexPath.row] as? UIImage
return cell
}
UICollectionView implementation is quite interesting. You can quite simple source code and video tutorial from these link :
https://github.com/Ady901/Demo02CollectionView.git
https://www.youtube.com/watch?v=5SrgvZF67Yw
class DummyCollectionCell: UICollectionViewCell {
#IBOutlet weak var userImageView: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DummyCollectionCell", for: indexPath) as! DummyCollectionCell
cell.titleLabel.text = nameArr[indexPath.row]
cell.userImageView.backgroundColor = .blue
return cell
}

Resources