In my code, I am trying to set the imageView of a UICollectionViewCell. The imageView is called cellImageView in the CollectionViewCell class. When the app loads up it tries to initialize this value, but it doesn't work
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "selectCell", for: indexPath) as! PhraseSelectionCell
cell.cellImageView?.image = UIImage(named: "lol")
return cell
}
Class of UICollectionViewCell
class PhraseSelectionCell: UICollectionViewCell {
#IBOutlet var cellImageView: UIImageView!
}
try debugging this way, then you can find where the bug is.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "selectCell", for: indexPath) as! PhraseSelectionCell
//debug 1
if UIImage(named: "lol") == nil {
print("image is nil, double check image name")
}
//debug 2
if cell.cellImageView == nil {
print("cellImageView outlet is nil")
}
cell.cellImageView?.image = UIImage(named: "lol")
return cell
}
Related
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
My CollectionViewCell imageView is nil
My Cell File is here
class MyTicketsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgTicket: UIImageView!
}
My Controller File Code is here
class MyTicketsCollectionViewController: UICollectionViewController {
var photos: [String] = ["ticket1","ticket2","ticket3","ticket4"]
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.register(MyTicketsCollectionViewCell.self, forCellWithReuseIdentifier: "MyTicketsCollectionViewCell")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photos.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyTicketsCollectionViewCell", for: indexPath) as! MyTicketsCollectionViewCell
cell.imgTicket.image = UIImage(named: photos[indexPath.row])
return cell
}
}
Error is "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
When I debug it then
cell.imgTicket is nil
How solve this issue?
Try changing your code to
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyTicketsCollectionViewCell", for: indexPath) as! MyTicketsCollectionViewCell
cell.imgTicket.image = UIImage(named: photos[indexPath.row])
return cell
}
You are dequeuing ActiveTicketsCollectionViewCell but the cell is registered under MyTicketsCollectionViewCell.
There is 2 possible solutions here...
1. Might be ActiveTicketsCollectionViewCell have not the property imgTicket or you mention a wrong cell class here as u have mentioned a different cell class name MyTicketsCollectionViewCell so try to write this code.
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyTicketsCollectionViewCell", for: indexPath) as! MyTicketsCollectionViewCell
cell.imgTicket.image = UIImage(named: photos[indexPath.row])
return cell
2. Might be you have missed to connect your property (#IBOutlet weak var imgTicket: UIImageView!) with the Outlet (xib or storyboard).
I have a UICollectionViewCell defined like so:
import UIKit
class GalleryCellCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var image: UIImageView!
}
Xcode put this in automatically when I added the outlet. In my UICollectionViewController's
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
function, I then try to set an image. My code is
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! GalleryCellCollectionViewCell
let imagePackage = imagePackages?[indexPath.item]
let uiImage = imagePackage?.getUIImage()
cell.image.image = uiImage
return cell
}
In my variable viewer for the debugger, I can see that uiImage is not nil. However, cell.image is nil. Why would this be? Did I not link it up correctly in the storyboard?
You can access image with another approach using tag.
from Interface builder (IB) of the cell go to attribute tab (third tab) and set tag for the image (like 5)
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! GalleryCellCollectionViewCell
let imagePackage = imagePackages?[indexPath.item]
let uiImage = imagePackage?.getUIImage()
var cellImg:UIImageView = cell!.viewWithTag(5) as! UIImageView;
cellImg.image = uiImage
return cell
}
I created an imageView in a collection view cell this way:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
let imageView: UIImageView = UIImageView(image: UIImage(named: "image"))
cell.contentView.addSubview(imageView)
return cell
}
The collection view has 2 cells, now I need to change the image of the first cell to Batman and the second to Superman, how should I achieve it?
First of all you shouldn't add subviews in cellForRowAtIndexPath. These code should be in creation of your custom cell.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
switch(indexPath.row) {
case 1: cell.imageView.image = UIImage(named: "batman")!
case 2: cell.imageView.image = UIImage(named: "superman")!
default: cell.imageView.image = UIImage(named: "placeholder")!
}
return cell
}
You need compare indexPath.row
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
var image = UIImage(named: "Superman")!
if indexPath.row == 0 {
image = UIImage(named: "Batman")!
}
cell.imageView.image = image!
return cell
}
Create your subclass of UICollectionViewCell
class CustomCell: UICollectionViewCell {
#IBOutlet var imageView : UIImageView!
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
}
}
And in viewDidLoad method
func viewDidLoad() {
collectionView.registerClass(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
}
You can try this code, I hope this works for you
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellIdentifier", forIndexPath: indexPath)
var imageView: UIImageView? = cell.contentView.viewWithTag(1111) as? UIImageView
if (imageView != nil) {
//switch/case, if/else whatever you want to set images accordingly
imageView!.image = UIImage(named: "image")
} else {
imageView = UIImageView()
imageView!.tag = 1111
cell.contentView.addSubview(imageView!)
}
return cell
Thank you all for the answers! But the above answers are either a little complicated, or not working on my side, so I'm giving my own solution, inspired by #HDT:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
if cell.contentView.subviews.count != 0 {
cell.contentView.subviews[0].removeFromSuperview()
}
switch indexPath.row {
case 0:
cell.contentView.addSubview(UIImageView(image: frontImage))
case 1:
cell.contentView.addSubview(UIImageView(image: backImage))
default:
cell.contentView.addSubview(UIImageView(image: UIImage(named: "Image")))
}
return cell
}
In Table view we can put checkmark easily on cells.
But in Collection View how can we put check mark, when we select a cell (image)?
I just took a image view inside the cell and image view and put a tick mark image. My code is below.
But it's not working.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
// handle tap events
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! customCollectionViewCell
if(cell.checkMarkImage.hidden == true)
{
print("Hidden")
cell.checkMarkImage.hidden = false
}
else
{
cell.checkMarkImage.hidden = true
print("No Hidden")
}
}
//Delegate Method cellForItemAtIndexPath
func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) ->
UICollectionViewCell
{
//Get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
"pickSomecell",
forIndexPath: indexPath) as! pickSomeGridViewController
//Show Images in grid view
cell.cellImage.image = self.arrAllOriginalImages[indexPath.row]
as? UIImage
//Check Mark toggle.
cell.toggleSelected()
//return cell.
return cell
}
And in pickSomeGridViewController show checkMark image selected or not.
class pickSomeGridViewController: UICollectionViewCell{
//Outlet of cell image.
#IBOutlet var cellImage: UIImageView!
//Outlet of checkMark image.
#IBOutlet var cellCheckMarkImage: UIImageView!
//Function for select and deselect checkmark.
func toggleSelected ()
{
//If image is selected.
if (selected)
{
//Show check mark image.
self.cellCheckMarkImage.hidden = false
}
else
{
//Hide check mark image.
self.cellCheckMarkImage.hidden = true
}
}
}
I see two main problems with this code:
You use dequeueReusableCellWithReuseIdentifier method which obtains different cell from collection view cache, not the one on screen.
Use cellForItemAtIndexPath method of collection view instead.
You try to save cell's state (selected/not selected) in the cell itself. It's common mistake when working with UITableView/UICollectionView and this approach will not work. Instead, keep the state in some other place (in dictionary, for example) and restore it every time collection view calls your data source cellForItemAtIndexPath method.
var arrData = NSMutableArray()
// 1.Make a ModalClass.swift and NSArray with modal class objects like this
class CustomModal: NSObject {
//Declare bool variable for select and deselect login
var is_selected = Bool()
//you can declare other variable also
var id = Int32()
}
// 2. custom array with modal objects
override func viewDidLoad() {
super.viewDidLoad()
let arrTemp = NSArray()
arrTemp = [1,2,3,4,5,6,7,8,9,10]
for i in 0 ..< arrTemp.count{
let eventModal = CustomModal()
eventModal.is_selected = false
eventModal.id = arrTemp[i]
arrData.add(eventModal)
}
tblView.reloadData()
}
// 2. Use collection view delegate method
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let modal = arrData[indexPath.row] as! CustomModal()
modal.is_selected = true
self.arrData.replaceObject(at: indexPath.row, with: modal)
tblView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let modal = arrData[indexPath.row] as! CustomModal()
modal.is_selected = false
self.arrData.replaceObject(at: indexPath.row, with: modal)
tblView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! YourCellClass
let modal = arrData[indexPath.row] as! CustomModal
if modal.is_selected == true{
cell.imgView.image = UIImage(named:"selected_image")
}else{
cell.imgView.image = UIImage(named:"deselected_image")
}
}
#Kishor, paintcode is the third party tool through which you can do that. I have provided the link too. since by default you don't have this facility, you should make your custom behavior to achiever this. Thanks.
Swift 4
In ViewController
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCollectionViewCellID", for: indexPath as IndexPath) as! YourCollectionViewCell
cell.someImageView.image = imgArr[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
let cell = collectionView.cellForItem(at: indexPath) as? YourCollectionViewCell
cell?.isSelected = true
cell?.toggleSelected()
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as? YourCollectionViewCell
cell?.isSelected = false
cell?.toggleSelected()
}
In YourCollectionViewCell
class YourCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var someImageView: UIImageView!
#IBOutlet weak var checkImageView: UIImageView!
//Function for select and deselect checkmark.
public func toggleSelected() {
if (isSelected == false) {
//Hide check mark image.
self.checkImageView.image = UIImage(named: "unCheckImage")
isSelected = true
}else{
//Show check mark image.
self.checkImageView.image = UIImage(named: "CheckImage")
isSelected = false
}
}
}
Hope enjoy!!
var selectedCellIndex:Int?
take variable if you want to show selected Item after reloadData() : which is previously selected CellItem. {inspired by above answer }
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColorCollectionCell", for: indexPath) as! ColorCollectionCell
cell.isSelected = false
if selectedCellIndex == indexPath.item {
cell.checkMarkImgView.image = UIImage(named: "icn_checkMark")
}else {
cell.toggleSelected()
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! ColorCollectionCell
cell.isSelected = true
selectedCellIndex = indexPath.item
cell.toggleSelected()
}
In CollectionViewCell u can use this method
class ColorCollectionCell: UICollectionViewCell {
#IBOutlet weak var cellimgView: UIImageView!
#IBOutlet weak var checkMarkImgView: UIImageView!
func toggleSelected() {
if (isSelected) {
self.checkMarkImgView.image = UIImage(named: "icn_checkMark")
}else{
self.checkMarkImgView.image = UIImage(named: "")
// here you can use uncheck img here i am not using any image for not selected.
}
}
}