Adding new Item to CollectionView programmatically, via the last Item - ios

I'm facing an issue with CollectionView, I want to see a collection of images and have an add button as the last item so first of all I've made an array of NSData as I'm gonna save those images to Core Data
var photoArray = [NSData]()
then I implement UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == photoArray.count + 1 {
present(imagePicker, animated: true, completion: nil)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photoArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.item
if indexPath.item == photoArray.count + 1 {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.item]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}
Actually I'm facing with the problem in "cellForItemAt indexPath" like "fatal error: index is out of range" I tried to make array look like var photoArray: [NSData]! but it caused other problems, please give me any advice or help, thank you!

Index is out of range because items or rows are indexed from 0
Should be like this:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoItem", for: indexPath) as? PhotoCell else {return UICollectionViewCell()}
cell.btn.tag = indexPath.row
if indexPath.row == photoArray.count {
cell.thumImage.image = UIImage(named: "add_button")
cell.btn.isHidden = true
print("first")
return cell
} else {
let img = photoArray[indexPath.row]
cell.configureAddingImage(img: img)
print("second")
return cell
}
}

Related

Swift Filtering data with collectionview

So im trying to filter my collectionview data using another collectionview, something like this
as from the picture on i try to make a filter button so i can filter the data base on the button that user tap, and the way im trying to make that filter button is to use another collectionview, but i dont know how to implement it.
so far here's my code :
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == homeColView {
return homeVm.heroList.count
}else if collectionView == filterColView {
return homeVm.filterRoles.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == homeColView{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
let data = homeVm.heroList[indexPath.row]
let imgUrl = URL(string: BASE_URL + data.img)
cell.heroNameLabel.text = data.localized_name
cell.heroImage.kf.setImage(with: imgUrl)
return cell
}else if collectionView == filterColView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCollectionCell", for: indexPath) as! FilterCollectionCell
cell.filterLabel.text = homeVm.filterRoles[indexPath.row]
return cell
}
return collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionCell", for: indexPath) as! HomeCollectionCell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == homeColView {
let vc = HeroDetailsVc()
vc.heroDetailsVm.heroDetails = homeVm.heroList[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
collectionView.deselectItem(at: indexPath as IndexPath, animated: true)
}else if collectionView == filterColView {
}
}
can anyone help me how to make this filter with collectionview?
Thank you

How to use two CollectionView in one ViewController?

I am working on an existing project which has a collectionView, right now i want to add another collectionView in this same viewcontroller. Already tried different solutions but can not seem to have any luck. Here is the existing code for collectionview:
func numberOfSections(in collectionView: UICollectionView) -> Int {
if homeList.last?.catList.isEmpty ?? false{
return homeList.count - 1
}
return self.homeList.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == homeList.count - 1{
return 2
}
return homeList[section].catList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == homeList.count - 1{
let doctorsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "doctorCell", for: indexPath) as! DoctorsCVC
doctorsCell.docDelegate = self
doctorsCell.docList = homeList[indexPath.section].catList as? [Doctor] ?? []
delayOnMain(0.1){
doctorsCell.docCollectionView.reloadData()
}
return doctorsCell
}
else{
let productsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductCVC
productsCell.setData(homeList[indexPath.section].catList[indexPath.row])
productsCell.fivePercentView.layer.cornerRadius = 5
return productsCell
}
}
And here is my new code for collectionView:
#IBOutlet var collectionView2: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.img.image = arrData[indexPath.row].image
return cell
}
Can someone help me to merge this code!
What I think is a clearer method is to use a second collectionViewController and a custom container view controller.
That way, the differentiation in the delegate methods is no longer needed.
You can't use two same collectionView delegate methods (eg -cellForItemAt ) methods in same view controller. So you have to check the collection view inside every collectionView delegate methods.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionView2 {
return arrData.count
} else {
if section == homeList.count - 1 {
return 2
}
return homeList[section].catList.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionView2 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.img.image = arrData[indexPath.row].image
return cell
}else{
if indexPath.section == homeList.count - 1{
let doctorsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "doctorCell", for: indexPath) as! DoctorsCVC
doctorsCell.docDelegate = self
doctorsCell.docList = homeList[indexPath.section].catList as? [Doctor] ?? []
delayOnMain(0.1){
doctorsCell.docCollectionView.reloadData()
}
return doctorsCell
}
else{
let productsCell = collectionView.dequeueReusableCell(withReuseIdentifier: "productCell", for: indexPath) as! ProductCVC
productsCell.setData(homeList[indexPath.section].catList[indexPath.row])
productsCell.fivePercentView.layer.cornerRadius = 5
return productsCell
}
}
}

reuse UITableViewCell with diferent data

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
}

Swift CollectionView first cell add user button and other cell load from image array

In my case, I am trying to create a UICollcetionView with first cell add button for add user and from second cell I need to load Image array string into another cells. Here, I am using two separate cell but I am not getting first cell into my output. Please provide me solution or another best method.
I am trying to get below output
Multiple Cell Code
// MARK: CollectionView Delegate
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let firstCell = collectionView.dequeueReusableCell(withReuseIdentifier: "addusercell", for: indexPath) as! AddParticipantsCollectionViewCell
return firstCell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "userscollectionview", for: indexPath as IndexPath) as! ParticipantsCollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
}
You need
if indexPath.item == 0 {
// first cell
}
else {
// second cell
cell.imageView?.image = self.imageArray[indexPath.item - 1]
}
Correct dataSource method ( remove it )
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1 // Section should set return 1 or default is optional
}
And change numberOfItemsInSection to
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count + 1
}
If you have two sections in the collectionView you also need to set the number of items in each individual section:
// MARK: CollectionView Delegate
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 1 // return 1 item in cell (+ cell)
} else {
return imageArray.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.section == 0 {
let firstCell = collectionView.dequeueReusableCell(withReuseIdentifier: "addusercell", for: indexPath) as! AddParticipantsCollectionViewCell
return firstCell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "userscollectionview", for: indexPath as IndexPath) as! ParticipantsCollectionViewCell
cell.imageView?.image = self.imageArray[indexPath.row]
return cell
}
}
I hope it's been of any help.

Firebase storage data showing twice

Trying to load data in collection view with this method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if urls.count == 0 {
return UICollectionViewCell()
}
let url = urls[indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! ImageCollectionViewCell
storageRef.reference(withPath: url).getData(maxSize: 15 * 1024 * 1024, completion: { data, error in
if let data = data {
cell.imageView.image = UIImage(data: data)
}
})
return cell
}
The thing is - at first i can see both cells without data, then completion get called, an i'm getting a data, but the first image in both cells.
How can i do it right? And how can i get metadata in the same time too?
Screenshot:
UPD:
I wrote an array
var datas = ["first", "second", "third", "fourth"]
An changed cell code to
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! ImageCollectionViewCell
cell.nameLabel.text = datas[indexPath.item]
return cell
}
And got this:
Still can't see what's wrong. My overrided methods:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return datas.count / 2
}
SOLVED. Should return numberOfSections = 1
I think the problem is that you're downloading the information in the cellForItemAt indexPath: function and you should download the images in another function like this
//Variable to store the UIImages
var images = [UIImage]()
//function to download the images, run it in the viewdidload like self.getImages()
func getImages(){
for url in self.urls{
storageRef.reference(withPath: url).getData(maxSize: 15 * 1024 * 1024, completion: { data, error in
if let data = data {
self.images.append(UIImage(data: data))
}
})
}
self.YourCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if urls.count == 0 {
return UICollectionViewCell()
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = self.images[indexPath.row]
return cell
}
Should return 1 in numberOfSection func
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
}

Resources