I have a collection view embedded in a table view so it scrolls vertically and horizontally. It has four sections, Today, This Week, This Month, This Year. I am having trouble understanding how to populate each section with its own data. Right now I am using the below code to populate the collection view but all sections have the same data. How can I populate each section with with its own data?
So if I had an array of images for Today, an array of images for This Week, an array of images for This Month, and and array of images for This Year, how can I set the image view in its section to the items in the corresponding array? So Today should have the images in the todayImageArray, This Week should have the images in the thisWeekImageArray and so on.
Also I have the delegate and data source of the collection view set to the table view.
Any help is much appreciated!
let images: [[UIImage]] = [
[image_1, image_2, image_3, image_4],
[image_5, image_6, image_7, image_8],
[image_9, image_10, image_11, image_12],
[image_13, image_14, image_15, image_16]
]
func numberOfSections(in collectionView: UICollectionView) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images[section].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = images[indexPath.section][indexPath.row]
return cell
}
You need a structured data source. Currently, from your code, it looks like you have a single array called images and you're using that to both provide the number of items and also to update cell content. But if you need separate sections, you need to model your datasource as such and provide logical responses to datasource and delegate methods in collectionView.
Example simple data source:
let simpleDataSource: [[UIImage]] = [
[image1, image2],
[image3, image4],
[image5, image6]
]
Example of using this in collectionView methods:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return simpleDataSource.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return simpleDataSource[section].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = simpleDataSource[indexPath.section][indexPath.row]
return cell
}
You should also read through the documentation for UICollectionView.
Set up an array that has all your images, or better yet structs designed to organize your information better, or image names as in my example, and then use the numberOfSections and indexPath.section properties to assign those images:
let images = [
["imageA1", "imageA2"],
["imageB1", "imageB2"]
]
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return images[section]
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images[section].count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCollectionViewCell
cell.imageView.image = UIImage(named: images[indexPath.section][indexPath.row])
return cell
}
Related
I want to create a collectionView with two different cells. The first cell should be displayed one time and the second should be displayed as often as the array is large. The result should be something like in the image in the attached link. Here is also a example code for better understanding my problem. Thanks to everyone who helps me!!! 🙂
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch indexpath { // No indexpath in numberofitemsinsection!
case 0:
return 1 //display one time the first cell
default:
return images.count // display as often as the array is large the second cell
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.row {
case 0:
let cell = imageCollectionView.dequeueReusableCell(withReuseIdentifier: "addImageCell", for: indexPath)
return cell
default:
let cell = imageCollectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell
cell.imageView.image = images[indexPath.row]
cell.delegate = self
cell.selectedAtIndex = indexPath
return cell
}
}
Here is the collectionView I want to create
You can achieve this inside cellForItemAt and you need to change numberOfItemsInSection like below:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return 1 more than our data array (the extra one will be the "add item" cell)
return dataSourceArray.count + 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// if indexPath.item is less than data count, return a "Content" cell
if indexPath.item < dataSourceArray.count {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ContentCell", for: indexPath) as! ContentCell
// configure your ContentCell: cell. <attribute>
return cell
}
// past the end of the data count, so return an "Add Item" cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AddItemCell", for: indexPath) as! AddItemCell
// configure your AddCell: cell. <attribute>
return cell
}
For that you need to create a ContentCell and AddItemCell and also have a dataSourceArray to store all data you need.
Why don't you use this?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1 + theArray.count
}
I have a double direction scrolling collectionView with 50 sections, 10 items per section and 3 showing cells per section and filling the collectionView with the same data array.
the problem is the collectionView duplicate data in every section and I want to show different data in appearing sections to the user.
Any help please!
this is my code:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 50
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: contentCellIdentifier,
for: indexPath) as! UserCollectionCell
cell.userImageView.kf.setImage(with: URL.init(string: String().loadCorrectUrl(url:firebaseUsers[indexPath.row].image)))
cell.userNameLabel.text=firebaseUsers[indexPath.row].name
if(selectedIndexPaths.contains(indexPath) ){
cell.userBackgroudView.isHidden=false
}
else{
cell.userBackgroudView.isHidden=true
}
}
return cell
}
Implement prepareForReuse in UserCollectionCell and clear the imageView and label text to prevent showing duplicate data on scroll
class UserCollectionCell: UICollectionViewCell {
override func prepareForReuse() {
super.prepareForReuse()
self.userImageView.image = nil
self.userNameLabel.text = nil
}
}
Hope it helps
I am practicing some coding on collectionViews. However I like to work in Main.storyboard to see what I am working with visually. Unfortunately it appears that makes more work on my end when working in the viewController because this would have been much faster if done programmatically.
I am trying to call for multiple reuse identifiers for the collectionViewCell. However I only know how to call one cell. Now I am not getting any errors, I just do not know how to display all of the cells when I run the program.
Here is the code.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Fashion Cell 0", for: indexPath)
return cell
}
When I run the app I get this.
Please note, in Main.Storyboard I am add the cells manually.
Example:
Do in this way
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Fashion Cell 0", for: indexPath)
return cell
}
if indexPath.item == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Fashion Cell 1”, for: indexPath)
return cell
}
//……
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Fashion Cell 0", for: indexPath)
return cell
}
Although you can use switch instead of if for better readability
You can not in this way.Create one array of your number of images and set it to collectionView. No need to more cell in storyboard.
let video:[UIImage] = ["","","",""]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return video.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)as! yourcellfile
let image = video[indexPath.row]
cell.img.image = image
return cell
}
You can go this way. It's proper method to imaplement collectionview.
I need to create a UIcollectionview with grids of cells with 3 cells per row. After a certain amount of cells, lets say 60, I need to display a big cell with image view cell 61(different set of data). But with creating this 61st cell of image, my normal data on 61st will be merged into this image cell, is there any way to calculate it without compromising my array of data . Thanks.
Here's the data source part:
var items = [Item]()
func numberOfSections(in collectionView: UICollectionView) -> Int {
let numberOfSections = 60/(items.count+1) + 1
return numberOfSections
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let numberOfSections = 60/(items.count+1) + 1
if section != numberOfSections - 1 {
return 60
}
let numberOfItems = items.count%60
return numberOfItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let itemIndex = indexPath.section * 60 + indexPath.row
let item = items[itemIndex]
// set cell from item …
}
Then you need to provide the header cell using UICollectionViewDelegate:
func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath)
Search SO for 'willDisplaySupplementaryView' will show you how to implement this. Good luck!
I have a collection view cell and inside there's an imageView. On it I display array of images using sd_setImage once loaded from firestore. In console I see all images which my app downloaded.
I use this code:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newDetailCollectionCell", for: indexPath) as! NewDetailCollectionViewCell
cell.imageView.sd_setImage(with: URL(string: images[indexPath.item]))
return cell
}
When I use this code I can't see my images. But if I use the code below everything works fine.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newDetailCollectionCell", for: indexPath) as! NewDetailCollectionViewCell
cell.imageView.sd_setImage(with: URL(string: images[indexPath.item]))
return cell
}
The problem is that you should be calling collectionView.reloadData() instead of tableView.reloadData() in your Dispatch.main.async {} Because in this situation the collectionView needs to update the dataSource. I Hope this helps.
DispatchQueue.main.async {
self.collectionView?.reloadData()
}