I have UICollectionView, I am downloading images and displaying them in the cells. My first cell is of screen width and contains a button, rest are the general cells. The application only deques the first 2 cells, There are supposed to be 3 cells.
My cellForItemAtIndexPath function:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == 0 {
print("yay")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UploadNewCell", for: indexPath) as! UploadNewCell
return cell
}else if indexPath.row > 0 {
let userImages = userposts[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProfileCell", for: indexPath) as! ProfileCell
cell.fillCells(uid: uid!, userPost: userImages)
return cell
}else{
return ProfileCell()
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.row == 0 {
print("hellowold")
} else {
let selecteditem : String!
selecteditem = userposts[indexPath.row]
performSegue(withIdentifier: "lol", sender: selecteditem)
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return userposts.count
}
my view:
There are supposed to be 3 images down there in the cells, One of them is dequed in the first index.
I am out of Ideas, Any ideas on the solution?
let userImages = userposts[indexPath.row]
At this point in your code, indexPath.row is > 0.
Arrays are 0-based, so the first cell (indexPath.row == 1) is getting the second item in your array (user posts[1]), which is the second image you wanted.
I can think of a couple of simple changes:
Change the index you're accessing, such as:
let userImages = userposts[indexPath.row - 1]
Add 1 to your userposts.count value in numberOfItemsInSection:
Split your collectionView into having multiple sections, so the top cell (UploadNewCell) is section 0, and the bottom three ProfileCells are a second section: this allows you to check the indexPath.section, and assign directly from row:
let userImages = userposts[indexPath.row]
Note: I would actually advise further modifying the code for the second option to create an enum for SectionType. That allows you to perform a switch over the potential values, allowing you to avoid that nasty default implementation, and boosts the readability of your code.
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 one UICollectionView in my UIView. What I'm trying to do is when user press the button then other items(images array) appear on same UICollectionView.
Let's say I have two arrays of items:
let items = [UIImage(named: "moses-vega-436582-unsplash"),
UIImage(named: "april6"), UIImage(named: "april4"), UIImage(named:
"april5")]
let items2 = [UIImage(named: "test01"), UIImage(named: "test02")]
Now when user press the button I want to update my collectionView with images from items2. I'm using basic code for collections (it's easy for me to detect which labels for example to show. Because I have variable called "Testas" and if it's 0 then I know that it's default collectionView and else it's .... :
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
if Testas == 0 {
cell.image.image = items[indexPath.item]
if indexPath.item == 0 {
cell.label.text = "One"
}
if indexPath.item == 1 {
cell.label.text = "Two"
}
if indexPath.item == 2 {
cell.label.text = "Collection 3"
}
if indexPath.item == 3 {
cell.label.text = "Rainy Days"
}
} else {
cell.image.image = items2[indexPath.item]
if indexPath.item == 0 {
cell.label.text = "White"
}
if indexPath.item == 1 {
cell.label.text = "Blue"
}
}
return cell
}
In conclusion, I'm asking what I need to write to pass items2 into collectionView when the user press the button and how to make this collectionView appear? (because it's not a function or something what I could call easily I guess). Keep in mind that I have a function where it counts items. So that's the biggest problem. I need a function to count my items2 when user press the button and then make images appear.
Thank you so much. Maybe it's not even possible to make what I want this way. I don't know.
You could accomplish this easily by creating an enum, and then simply toggling it's value when the button is pressed followed by a collectionView.reloadData()
Here is your enum:
enum ItemType : Int {
case items = 0,
items2 = 1
}
Declare it like this:
var itemType : ItemType = .items
Your collectionView functions would look something like this:
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return itemType == .items ? items.count : items2.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
switch itemType {
case .items:
// code for items array
default:
// code for items2 array
}
return cell
}
Your button press:
#IBAction func onButtonPressed(_ sender: Any) {
itemType = .items2
collectionView.reloadData()
}
If you have more than 2 arrays you will need to update your collectionView functions to something like this:
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
switch itemType {
case .items:
return items.count
case .items2:
return items2.count
case .items3:
return items3.count
default:
return items4.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
switch itemType {
case .items:
// code for items array
case .items2:
// code for items2 array
case .items3:
// code for items3 array
default:
// code for items4 array
}
return cell
}
I am currently working on a project where I have one CollectionViewController and multiple cells registered. I need assistance with returning the number of cells I want to be shown for the each cell.
For Example I have registered:
collectionView?.register(PhotoCell.self, forCellWithReuseIdentifier: picCell)
collectionView?.register(ArticleCell.self, forCellWithReuseIdentifier: articleCell)
As you can see I have registered two cells. How can I return 7 photo cells and 4 article cells to be displayed in my collection view programmatically?
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
As of right now I am only able to return 7 photo cells successfully.
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! PhotoCell //Default will never Execute
if data == photo (
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! PhotoCell
return cell )
else if data == article {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! articleCell
return cell
}
return cell
}
use this approach to determine the cell type . Here Your data if its audio than that cell weill be used and if its article than other cell will be used and count return will be total data count.
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 11
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
if (indexPath.row < 7)
{
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: picCell, for: indexPath) as? PhotoCell
{
//your code here
return cell
}
}
else if (indexPath.row > 6)
{
//if indexing is needed create new index starting at 0
let articeCellindex = indexPath.row - 7
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: articleCell, for: indexPath) as? ArticleCell
{
return cell
}
}
else
{
return UICollectionViewCell()
}
}
Amey's answer is fine but they omitted how to structure your cell data in a way so that both cell types are contained in one structure. An alternative is to explicitly state which rows will display the cell data. Make sure both the picCell and articleCell reuse identifiers refer to the same cell.
I have an app with 2 different arrays that usually have 2 different item counts. For some reason the first collection view is getting the item count of the second collection view unless I get rid of the second collection view.
My code:
<script src="https://pastebin.com/embed_js/NAtgb3kp"></script>
Steps:
1. say your collection are
var albumsViewCollectionView, songsViewCollectionView : UICollectionView!
Register the nib files for your 2 collectionviews
your collectionview datasource method
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionview == albumsViewCollectionView {
return albumCount
}
else if collectionview == songsViewCollectionView {
return songsCount
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == albumsViewCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AlbumsViewCollectionView", for: indexPath) as! AlbumsViewCollectionView
return cell
}
else if collectionView == songsViewCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SongsViewCollectionView", for: indexPath) as! SongsViewCollectionView
return cell
}
return UICollectionViewCell()
}
Trying to get my head around collection views, arrays, and dictionaries. I have a class named CollectionViewCell that contains a UIImageView outlet that I want images from an array to populate. The trouble is that I have different sections with different content so I created multiple arrays that store the images. With the present code I get an error saying the array index is out of range. Do I need to populate the different sections with a dictionary that separates the information with keys and values instead?
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as CollectionViewCell
// Configure the cell
cell.imageView.image = green[indexPath.row]
cell.imageView.image = blue[indexPath.row]
return cell
How can I name the different sections with headers that are populated from an array? names is my array of strings and HeaderView is a class containing an empty label. I also get an error using this code.
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionElementKindSectionHeader:
let headerView =
collectionView.dequeueReusableSupplementaryViewOfKind(kind,
withReuseIdentifier: "HeaderView",
forIndexPath: indexPath)
as HeaderView
headerView.label.text = names[indexPath.row]
return headerView
default:
assert(false, "Unexpected element kind")
}
}
[edit]
The number of sections and number of items in section code:
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
//Return the number of sections
return 2
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Return the number of items in the section
return green.count
}
So if there's a different number of items in blue section as opposed to green, do I include return blue.count as well in the numberOfItemsInSection function?
Since green and blue are supposed to populate different sections, you need to use one or the other conditionally depending on the section, ex:
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Return the number of items in the section
if section == 0 {
return green.count
} else {
return blue.count
}
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as CollectionViewCell
// Configure the cell
if indexPath.section == 0 {
cell.imageView.image = green[indexPath.row]
} else {
cell.imageView.image = blue[indexPath.row]
}
return cell
}
In your current code, if blue is a shorter array than green, you can get the error you described, since the numberOfItemsInSection goes beyond blue's index.
The indexPath object encapsulates information not only about the row, but also about the section. So, if you are referring to the first element in the first section, the indexPath.row will be 0 and indexPath.section will be 0. If you are referring to the third element in the second section, indexPath.row will be 2 and indexPath.section will be 1 ... and so on. In this context, how would you define cellForRowAtIndexPathand numberOfItems methods? Here is the code:
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Return the number of items in the section
if(section == 0) {
return green.count
} else if(section == 1) {
return red.count
}
}
tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!) {
//Reusable cell code
if(indexPath.section == 0) {
//green cell population
}
else if(indexPath.section == 1) {
//red cell population
}
}