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()
}
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 two custom cell classes HomeCell & CreateCell. Ideally, the first cell should be the CreateCell & the HomeCell's should start at the index of '1' (After the first create cell) but currently, the CreateCell and the first HomeCell are overlapping. Is there a way I can set the HomeCell's to start at the index of '1'?
If there is any more code that needs to be provided, let me know.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.row == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CreateCell", for: indexPath) as! CreateCell
//configure your cell here...
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell", for: indexPath) as! HomeCell
cell.list = lists[indexPath.item]
//configure your cell with list
return cell
}
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return lists.count
}
Since you want to access 0th element of List on 1st index, you would need to change the code a little bit in your cellForItemAt indexPath:
cell.list = lists[indexPath.item - 1]
in this way, you will start the HomeCell views from 1st index
Also You would need to change the count of total items, as there is additional create cell.
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return lists.count+1
}
Use indexPath.item in place of indexPath.row
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CreateCell", for: indexPath) as! CreateCell
//configure your cell here...
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCell", for: indexPath) as! HomeCell
cell.list = lists[indexPath.item]
//configure your cell with list
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 am trying on my viewDidLoad() to fetch images from my DB and then present the images, and highlight the first one.
My code thus far is:
profile?.fetchImages(onComplete: { (errors, images) in
for error in errors {
print("Error", error)
}
for imageMap in images {
self.photos.append(imageMap.value)
}
if self.photos.count < self.MAX_PHOTOS {
self.photos.append(self.EMPTY_IMAGE)
}
DispatchQueue.main.async {
self.photoCollectionView.reloadData()
}
self.updateSlideshowImages()
let indexPath = IndexPath(row: 0, section: 0)
let cell = self.photoCollectionView.cellForItem(at: indexPath)
if cell != nil {
self.setBorder(cell!)
}
})
However, for me cell is always nil, despite images existing and being fetched, and thus the setBorder is never called. Why is the cell always nil? I just want to set the border on the first cell.
You have placed self.photoCollectionView.reloadData() in async block so the let cell = self.photoCollectionView.cellForItem(at: indexPath) will run immediately before collection view reload, thats the reason you are getting nil for first cell.
You need to make sure that after collection view reload, I mean when all collection view cells are loaded then you can get and do your operations.
Alternatively, you can do this in cellForItemAtIndexPath like below...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier.jobCollectionViewCellIdentifier, for: indexPath) as! <#Your UICollectionViewCell#>
if indexPath.section == 0 && indexPath.row == 0 {
//highlight cell here
}
return cell
}
And if you want to highlight cell after all images load in collection view then you need to check for datasource of collection view.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = ...
if indexPath.row == arrImages.count-1 {
let newIndexPath = IndexPath(row: 0, section: 0)
if let cellImg = self.photoCollectionView.cellForItem(at: newIndexPath) {
self.setBorder(cellImg)
}
}
}
Instead of highlighting the UICollectionViewCell in viewDidLoad() after receiving the response, highlight it in willDisplay delegate method, i.e.
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
if indexPath.row == 0
{
cell.isHighlighted = true
}
}
And add border of cell in the isHighlighted property of UICollectionViewCell according to the cell highlight status, i.e.
class CustomCell: UICollectionViewCell
{
override var isHighlighted: Bool{
didSet{
self.layer.borderWidth = self.isHighlighted ? 2.0 : 0.0
}
}
}
You can use isSelected property the same way in case you want to change appearance of the cell based on the selection status.
Let me know if you still face any issue.
Set your cell's border in cellForRow method.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellIdentifier", for: indexPath) as! YourCustomCell
if indexPath.row == 0 {
self.setBorder(cell)
}
return cell
}
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.