Why is array in collection view getting multiplied by amount of sections? - ios

When I want to see an array in a collection view in swift, it gets multiplied by the amount of sections in the collection view. Why is this and how do I stop it?
let numbers = ["one", "two", "three"]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let theCell = collectionView.dequeueReusableCell(withReuseIdentifier: "theCell", for: indexPath) as! cell
for number in numbers {
print("\(number)")
}
return theCell
}
I hoped that it would return:
one
two
three
but instead it returned:
one
two
three
one
two
three
one
two
three

Since you have three cells per section, and assuming you have only one section, collectionView(_:cellForItemAt:) gets called three times. Each time you are printing all the elements of the numbers array. To only print the element corresponding to the current index, replace the for loop by:
print(numbers[indexPath.row])

Related

Creating tinder like card layout using UICollectionView

I am trying to recreate the tinder card stack which can then be swiped through. I have decided to do this using UIcollectionView.
I was going to make an array of user objects and within each, there would be an array of images. So for the number of sections, I would say arr.count and for the number of sub-sections arr[section].arrImg.count.
Currently, I have a problem where when I run the project I get a vertical stack of 5 images. I assume each image represents one cell. But I need these cells to be stacked on top of each other like tinder.
How can I do that (stacked on top of each other like tinder)?
The logic for making the card layout:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(peopleArr[section].arrOfProfileImages.count, "jfldhsajklfhsdkj")
return peopleArr[section].arrOfProfileImages.count
}
//This current version loads all people it should only return like 3...
func numberOfSections(in collectionView: UICollectionView) -> Int {
print("fkhdsgafhjdgsajhfgdsak", peopleArr.count)
return peopleArr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cardCell", for: indexPath) as! DatingCardCollectionViewCell
cell.imageView.image = UIImage(named: "ProfileImage")//peopleArr[indexPath.row].arrOfProfileImages[indexPath.section]
return cell
}

Swift UICollection view different number of cells per row

How can I have a UICollection View, with One cell in the first row, and three cells in the second row?
I want to display a picture in the first row, and below it 3 pictures.
You need to use collectionView's Datasource method number of section to specify how many section you required in your collectionview. in that section you can pass number of cell you want to display. and in cell for item you can set data according to section and Item value.
try like this.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3 // you can return as per your requirement
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 2 // number of cell you want to display in each section
}else if section == 1 {
return 3 // number of cell you want to display in each section
}else {
return 4 // number of cell you want to display in each section
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierCollection, for: indexPath) as! HomeCollectionViewCell
return cell
}
You need to implement your own custom layout. By default the collection view has UICollectionViewFlowLayout, that fills the cells in a horizontal/vertical grid.
You can change this behaviour with your own layout, i.e. a class implementing UICollectionViewLayout.
To get started, I would recommend checking this and this tutorials.

How to manage two different cells in a collection view

This is a really basic wireframe of what I'm trying to achieve:
This is what I currently have in Xcode, resulting in 3 cells per row, with no space in between. The date label cell isn't showing up because I don't know how to get cellForItem to recognize it along with the post cells (hence the question):
I have two separate cell classes - one for the date labels and one for the rows of images.
My collection view methods are as follows:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postCell", for: indexPath) as! PostCell
let dateCell = collectionView.dequeueReusableCell(withReuseIdentifier: "dateLabelCell", for: indexPath) as! DateLabelCell
cell.postImage.loadImageUsingCacheWithUrlString(posts[indexPath.row].pathToImage)
cell.postID = posts[indexPath.row].postID
cell.postImage.contentMode = UIViewContentMode.scaleAspectFill
// Here I'll have to get the date and have the labels display the days of the week properly
dateCell.dateLabel.text = "Monday"
return cell
}
But I'm not sure how to manage both cells in the above methods. I'll have to sort the posts by a timestamp so things posted on a certain day get added to the correct day's row, but that's something I'll do another day - for now I'm just wondering how I can get the UI laid out so that the collection view shows a date label, then a row of post cells, and repeat.
Thanks for any advice!

indexPath.row always returns zero

I have two collection view and one displays names and the other one displays age of the corresponding person. This data is stored inside array of dictionary in a form of "[["Name","Age"],["Name": "Daniel", "Age" : "20"],["Name":"Jake","Age":"20"]]. This data comes from CSV file, so the first element is a header. Inside collectionView cellForItemAtIndexPath, I'm checking collection view and provide data base on row number like cell[indexPath.row]["Name"] and cell2[indexPath.row]["Age"]. However, indexPath.row always returns zero, so I'm getting just headers -
How do fix this issue? This is my code -
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 2
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == self.nameCollectionView {
let nameCell = collectionView.dequeueReusableCellWithReuseIdentifier("NameCell", forIndexPath: indexPath) as! NameCell
nameCell.data.text = self.data?[indexPath.row]["Name"]
println(indexPath.row)
return nameCell
}
else{
let ageCell = collectionView.dequeueReusableCellWithReuseIdentifier("AgeCell", forIndexPath: indexPath) as! AgeCell
ageCell.data.text = self.data?[indexPath.row]["Age"]
return ageCell
}
}
As par your code you are setting numberOfItemsInSection only 1 then you always get 0th index. make there is dynamic value for example return Array.count.
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.data.count // here you need to set dynamic count of array
}
UPDATE:
If you followed numberOfSectionsInCollectionView then make your code like following of cellForRow:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == self.nameCollectionView {
let nameCell = collectionView.dequeueReusableCellWithReuseIdentifier("NameCell", forIndexPath: indexPath) as! NameCell
nameCell.data.text = self.data?[indexPath.section]["Name"]
println(indexPath.section)
return nameCell
}
else{
let ageCell = collectionView.dequeueReusableCellWithReuseIdentifier("AgeCell", forIndexPath: indexPath) as! AgeCell
ageCell.data.text = self.data?[indexPath.section]["Age"]
return ageCell
}
}
IndexPath is a property which has the following structure
Indexpath {Section, Row}.
So if you want your data in two different section with a single row in them then indexpath.row for each of them is going to return 0 as because
For section index 0 - Indexpath[0,0] meaning indexpath of section index 0 and row index 0
For section index 1 - Indexpath[1,0] meaning indexpath of section index 1 and row index 0
Hope could make you understand.
As others have pointed out, you are telling your collection views that you always have 2 sections and 1 item in each section. Thus the collection view will only ever ask for 1 item in each section. Thus there will only ever BE one item in each section (index 0).
You say "This data is stored inside dictionary in a form..."
Is it a dictionary or an array of dictionaries? A dictionary is an unordered collection, so it is not appropriate for storing an ordered set of items for feeding to a collection view or table view. An array of dictionaries is appropriate. From the data you show, and your code, it looks like you have an array of dictionaries. You should edit your question to make that clear.
Your code doesn't really make sense. You have 2 different collection views, and you have each display different data. You tell your collection views that you have 2 sections but ignore the section number and create the same data for both sections. Something is wrong there.

correct way of deleting items in collection view

I have a collection view of 20 items stored in pictures array. I am deleting selected items with this code:
self.collectionView.performBatchUpdates({
let selectedItems = self.collectionView.indexPathsForSelectedItems()!
self.picturesObject.deleteItemsAtIndexPaths(selectedItems)
self.collectionView.deleteItemsAtIndexPaths(selectedItems)
}, completion: {_ in})
this is the implementation of picturesObject's deleteItemsAtIndexPaths:
func deleteItemsAtIndexPaths(indexPaths:[NSIndexPath]){
for indexPath in indexPaths{
pictures.removeAtIndex(indexPath.item)
}
}
The problem I'm facing is the following. Every time a selected item in collection view is deleted, the pictures array gets smaller. If I delete the first item, than pictures array is only 19 items big. If I than try to delete item number 20 in collection view, the array index gets out of bounds because pictures array is now only 19 object big, but I wanted to delete the 20iest object stored in indexpath.item.
What is the correct way of deleting items in collection view?
EDIT:/// collection view methods
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
collectionView.allowsMultipleSelection = true
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return picturesObject.pictures.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! ShopCell
cell.imageView.image = picturesObject.pictures[indexPath.item]
return cell
}
Before looping through your array in deleteItemsAtIndexPaths, sort your indexPaths in descending order. Then, if you delete item number 19, the next to delete is guaranteed to be less than 19.

Resources