I have a custom dynamic cell on a collectionView created on IB which will be filled with data from an array.
I want to add a static cell on the same CollectionView IB. Is it possible that the static cell to be on the last object of Collection View, no matter what array length is from dynamic cell the static cell would be added as last object?
here is the code for doing this.. I tried this method... For dynamic cell and static cell...
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 2
}
// Retuens the number of sections in collectionview
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
if section == 0 {
return data.count
}else if section == 1{
return 1
}else {
return 0
}
}
// Data get's filled into UICollectionView
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
var cell : CollectionCell!// important step...
if indexPath.section == 0 {
cell = collectionView.dequeueReusableCellWithReuseIdentifier("collectionViewCell", forIndexPath: indexPath) as! CollectionCell
//do something inside this
}
else if indexPath.section == 1 {
cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CollectionCell
//here the static cell...
}
return cell
}
Related
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 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()
}
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.
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
}
}