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
}
I connect my swift app with firebase and now I'm trying to get item key of selected item from the collection view to store selected item to the cart.
import UIKit
import Firebase
import FirebaseDatabase
import SDWebImage
class ViewController6: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate{
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var itemCollectionView: UICollectionView!
var customItemFlowLayout: CustomItemFlowLayout!
var items = [itemsL]()
//var ind = 0
var dbRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
nextButton.layer.cornerRadius = 10
dbRef = Database.database().reference().child("items")
loadDB()
customItemFlowLayout = CustomItemFlowLayout()
itemCollectionView.collectionViewLayout = customItemFlowLayout
//itemCollectionView.backgroundColor = .white
}
func loadDB(){
dbRef.observe(DataEventType.value, with: { (snapshot) in
var newItems = [itemsL]()
for itemsLSnapshot in snapshot.children {
// condition for filtring items
if itemsL.init(snapshot: itemsLSnapshot as! DataSnapshot).key >= "2"{
// bring item
// #######
let itemsLObject = itemsL(snapshot: itemsLSnapshot as! DataSnapshot)
newItems.append(itemsLObject)
// #######
}
}
self.items = newItems
self.itemCollectionView.reloadData()
})
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt IndexPath: IndexPath) -> UICollectionViewCell {
let cell = itemCollectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: IndexPath) as! ItemCollectionViewCell
let item = items[IndexPath.row]
cell.imageView.sd_setImage(with: URL(string: item.url),placeholderImage: UIImage(named: "image22"))
cell.itemName.text = item.itemName
cell.price.text = item.price
cell.layer.borderColor = UIColor.gray.cgColor
cell.layer.borderWidth = 1
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderColor = UIColor.blue.cgColor
cell?.layer.borderWidth = 3
cell?.isSelected = true
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderColor = UIColor.gray.cgColor
cell?.layer.borderWidth = 1
cell?.isSelected = false
}
}
Your code selects and deselects the cell but the state is not persistent.
The most reliably way to make the selection persistent is to add a property in the model
struct ItemsL { // please name structs with starting capital letter
var isSelected = false
// other properties
}
In cellForItemAt select the cell depending on this property
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = itemCollectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: IndexPath) as! ItemCollectionViewCell
let item = items[indexPath.row]
cell.imageView.sd_setImage(with: URL(string: item.url),placeholderImage: UIImage(named: "image22"))
cell.itemName.text = item.itemName
cell.price.text = item.price
if item.isSelected {
cell.layer.borderColor = UIColor.blue.cgColor
cell.layer.borderWidth = 3
cell.isSelected = true
} else {
cell.layer.borderColor = UIColor.gray.cgColor
cell.layer.borderWidth = 1
cell.isSelected = false
}
return cell
}
In didSelectItemAt toggle isSelected and reload the item, didDeselectItemAt is not needed.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
items[indexPath.row].isSelected.toggle()
collectionView.reloadItems(at: [indexPath])
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
....
}
To get the selected items filter the array
let selectedItems = items.filter{ $0.isSelected }
I have 2 arrays with different data
var array : [String] = ["getMeals", "getMeasure", "getWorkouts"]
var array2 : [String] = ["getStep", "getStep", "getStep"]
I am trying to retrieve the images from arrays, but in different collection cells.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array[indexPath.row])
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array2[indexPath.row])
return cell
}
}
I need to create another UICollectionViewCell or I can use the current cell?
you can use the same cell, with this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
if indexPath.section == 0{
cell.collectionImage.image = UIImage(named: array[indexPath.row])
}else{
cell.collectionImage.image = UIImage(named: array2[indexPath.row])
}
return cell
}
You need 1 array like
let array = [["getMeals", "getMeasure", "getWorkouts"],["getStep", "getStep", "getStep"]]
func numberOfSections(in collectionView: UICollectionView) -> Int {
return array.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array[section].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WorkoutCollectionCell", for: indexPath) as! WorkoutCollectionCell
cell.collectionImage.image = UIImage(named: array[indexPath.section][indexPath.row])
return cell
}
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()
}
}
My code below would work if it was displayed on a label. But in this function I am getting the error message Missing return in a function expected to return 'UICollectionViewCell'. Putting the return cell in the for loop does not work.
import UIKit
class collectionVIEW: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var users = [User]()
#IBOutlet var theIssues: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// users = cdHandler.fetchObject()!
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return users.count
}
func getDefaultCell() -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cdHandler.fetchObject() != nil {
users = cdHandler.fetchObject()!
for c in users {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
cell.general.text = "\((cell.general.text)!)+\((c.userName)!)"
return cell
}
} else {
return getDefaultCell()
}
}
}
cellForItemAt method expects to return UICollectionViewCell in all cases. In the else condition, return a default cell as below:-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if cdHandler.fetchObject() != nil {
users = cdHandler.fetchObject()!
for c in users {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! whyCollectionViewCell
cell.general.text = "\((cell.general.text)!)+\((c.userName)!)"
return cell
}
}else{
return getDefaultCell()
}
Note:-Register collection view with identifier defaultCcell
func getDefaultCell() -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "defaultCcell", for: indexPath) as! UICollectionViewCell
return cell
}