collectionview cell for xib not showing - ios

I am trying to create a custom cell for my collection view. I have a xib named AccountCell:
In my view containing the collection view:
profileViewController = p;
collectionView.dataSource = profileViewController
collectionView.registerClass(SocialAccountCell.self, forCellWithReuseIdentifier: "accountCell")
and then in the data source:
func collectionView(_collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
println("getting cell")
let cell = _collectionView.dequeueReusableCellWithReuseIdentifier("accountCell", forIndexPath: indexPath) as! SocialAccountCell
cell.test()
return cell
}
func collectionView(_collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return user!.accounts.count
}
SocialAccountCell.swift:
class SocialAccountCell: UICollectionViewCell
{
func test()
{
println("Hello From collection cell")
}
}
Both "getting cell" and "Hello From collection cell" are printed but no blue cell appears in the collection view.
I tried adding an image to the cell to check if it was just the blue not working. Still no indication of any cell appearing.
What steps am I missing here?

Since you're using xib to define a cell, I think you'd use collectionView.registerNib(UINib(nibName: "someNib", bundle: nil), forCellWithReuseIdentifier: "accountCell"), or else you'd setup UI elements in code.

Related

How to have custom cell in UICollectionView

I have a UICollectionView that I want to make 3 custom cells appear.
I have read the documentation but I haven't been able to fix this issue.
Is there something I am missing?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
I have tried changing the return 1 to 3 to make 3 custom cells appear but it only makes the 1st custom cell appear 3 times.
I have created a video and linked the video below explaining my situation.
https://www.loom.com/share/9b5802d6cc7b4f9a93c55b4cf7d435bb
Edit I have used #Asad Farooq method and it seems to have worked for me. I added my CollectionView's shown below and I can now make custom cells!
if(indexPath.item==0)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DailyCollectionViewCell", for: indexPath) as! DailyCollectionViewCell
return cell
}
if(indexPath.item==1)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WeeklyCollectionViewCell", for: indexPath) as! WeeklyCollectionViewCell
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MonthlyCollectionViewCell", for: indexPath) as! MonthlyCollectionViewCell
return cell
}
}
As we can see from the documentation of Apple,
You typically don’t create instances of this class yourself. Instead, you register your specific cell subclass (or a nib file containing a configured instance of your class) using a cell registration. When you want a new instance of your cell class, call the dequeueConfiguredReusableCell(using:for:item:) method of the collection view object to retrieve one.
We have to register the cell to the collectionView before using it, for example:
class CustomCollectionViewCell: UICollectionViewCell {
// my custom collection view cell
}
Then we gonna register it to the collection view:
class MyViewController: UIViewController {
...
override func viewDidLoad(){
super.viewDidLoad()
...
self.myCollectionView.dataSource = self
// register the cells, so the collectionView will "know" which cell you are referring to.
self.myCollectionView.register(UINib(nibName: "CustomCollectionViewCell", bundle: nil), forCellReuseIdentifier: "customReuseIdentifier")
// register all type of cell you wanted to show.
}
}
extension MyViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return number of cell you wanted to show, based on your data model
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = routineCollectionView.dequeueReusableCell(withReuseIdentifier: "customReuseIdentifier", for: indexPath) as! CustomCollectionViewCell
// cast the cell as CustomCollectionViewCell to access any property you set inside the custom cell.
// dequeue cell by the reuseIdentifier, "explain" to the collectionView which cell you are talking about.
return cell
}
}
The above code snippet is just a brief example, but I hope that explain the idea.
If you got multiple type of custom cell, you'll have to create classes for them (sub-class of UICollectionViewCell), register them to your collectionView, and dequeue them in collectionView(cellForRowAt:).
There are plenty of tutorial on the internet, here share one of my favourite:
https://www.raywenderlich.com/9334-uicollectionview-tutorial-getting-started
Edit:
If you are using storyboard only to add your custom collectionViewCell, you don't need to register the cell again, the cell already existed in the collectionView (Sorry the above code is just my preference). Just set the class & identifier of the cell, and dequeue the cell using the identifier in collectionView(cellForRowAt:).
We have to register the three different custom cell to the collectionView before using it then inside this function add this code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath.item==0)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! cell1
return cell1
}
if(indexPath.item==1)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! cell2
return cell2
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell3", for: indexPath) as! cell3
return cell3
}

Assertion failure in UICollectionView inside UITableViewCell

My code has a UICollectionView inside a UITableViewCell. I have two different set of arrays named TopBrandArray & TopCategoryArray - which is being displayed in two different cells of a Table inside a collectionView.
The delegates and datasource has been connected to the HomeViewController in the main storyboard. Also, the name for the cells has been given.
There is no error while compiling the program but gets an expection while running the code.
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier TopCategoryCollectionID - must register a nib or a class for the identifier or connect a prototype cell in a storyboard
When I am trying to run by displaying only one single cell of the tableviewcell, the code works fine. But if am adding more cell the above mentioned error pops up. Here,I am adding the code:
#IBOutlet weak var homePageTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.homePageTable.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: "TopCategoryID", for: indexPath) as! TopCategoriesTableViewCell
cell.tablecollection1.reloadData()
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "BrandTableID", for: indexPath) as! BrandsTableViewCell
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 162
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0{
return topCategoryArray.count
}
else{
return topBrandArray.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TopCategoryCollectionID", for: indexPath) as? TopCategoriesCollectionViewCell{
cell.cat_image.image = UIImage(named: topCategoryArray[indexPath.row].image)
print(topCategoryArray[indexPath.row].name)
cell.cat_value.text = topCategoryArray[indexPath.row].name
return cell
}
else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BrandsCollectionID", for: indexPath) as! BrandsCollectionViewCell
cell.layer.borderWidth = 1.5
cell.layer.borderColor = UIColor.gray.cgColor
cell.layer.cornerRadius = 4
cell.brandimage.image = UIImage(named: topBrandArray[indexPath.row].image)
return cell
}
}
}
Since it is asking to register a nib or a class for the identifier, I do not know where inside the code should I write the code because when I wrote it in viewDidload(), an error popped up showing "Ambiguous reference to member collectionView(_:numberOfItemsInSection:)"
The issue is with the registration of the cell with collection view. The collection view is unable to dequeue cell with the "TopCategoryCollectionID" identifier. You need to say to collection view that I'm going to use this cell as collection view cell.
You need to register TopCategoryCollectionID cell to collection view.
let nib = UINib(nibName: "TopCategoryCollectionID", bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: "TopCategoryCollectionID")
If you have used cell in storyboard then no need to register cell again.
EDIT
As you have collection view inside your tableview cell so datasource and delegate of collection view must be implemented indie the respective cells.
You need to transfer the collection view code into table view cells.

Getting indexPath of tableView inside tableViewCell file during cell creation/dequeueing

I am creating a scrollable view filled with monthly calendars. I'm using a collection view to display a calendar inside a table view full of calendars. So each table view cell is a calendar for a specific month, and each collection view cell is a day. I have a separate swift file for the tableview cell from the view controller. Since each tableview cell is going to look different (because different months), the tableview cell needs to know which row it is placed in inside the tableview during its creation in dequeque cell function.
tableView.dequeueReusableCell(withIdentifier: "CalendarTableViewCell", for: indexPath)
I need to get the indexPath in the "for: indexPath" parameter inside the tableview cell file because the collectionview inside the tableview cell gets created when the tableview cell is dequeued. The contents of the collection view depends on which tableview row it's in. So how do I get that parameter?
Sorry for the long explanation, please help if possible. Thank you!
Create an array in UITableViewCell subclass and use that array in collection view data source methods.
class MonthCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
let datesArray = [String]()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return datesArray.count
}
}
In tableView cellForRowAt method assign the date values and reload the collectionView
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as! MonthCell
cell.datesArray = []//dates based on indexPath
cell.collectionView.reloadData()
return cell
}
Or
Assign a reference to the table view cell index path in tableView cellForRowAt method
class MonthCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
var tableIndexPath:IndexPath?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let tableIndexPath {
// return value based on tableIndexPath
} else {
return 0
}
}
}
//cellForRowAt
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MonthCell") as! MonthCell
cell.tableIndexPath = indexPath
cell.collectionView.reloadData()
return cell
}

Swift Reload CollectionView in Tableview Header with Xib

I try to implement detail view about a product. I use tableview for product details and I decide to create a collectionview for product images in the tableview header. I create a Xib file that includes a collection view and 2 labels. And I implemented this Xib to tableview header. I can reload the tableview rows but I didnt reload the collectionview in header.
How can I reload this collectionview?
I use this code after pulling json and it allows me show the paramters in tableview cells.
let sectionIndex = IndexSet(integer: 0)
self.tableView.reloadSections(sectionIndex, with: .none)
In viewDidLoad()
if element.result.productImages?.count ?? 0 > 0 {
for x in element.result.productImages! {
print(x)
self.productImages.append(x.imageUrl)
self.productDetailHeaderView.productImagesCollectionView.reloadData()
}
}
In CellForRowAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductImagesCollectionViewCell", for: indexPath) as! ProductImagesCollectionViewCell
cell.productImage.sd_setImage(with: URL(string: "\(productImages[indexPath.row])"), placeholderImage: UIImage(named: "placeholder"))
return cell
}
--
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let v : ProductDetailHeaderView = UIView.fromNib()
productDetailHeaderView = v
productDetailHeaderView.translatesAutoresizingMaskIntoConstraints = false
productDetailHeaderView. productImagesCollectionView.register(UINib(nibName: "ProductImagesCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "ProductImagesCollectionViewCell")
productDetailHeaderView.backgroundColor = .yellow
return productDetailHeaderView
}
Thanks in advance.
You may need to set the delegate and dataSource
productDetailHeaderView.productImagesCollectionView.register(UINib(nibName: "ProductImagesCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "ProductImagesCollectionViewCell")
productDetailHeaderView.productImagesCollectionView.delegate = self
productDetailHeaderView.productImagesCollectionView.dataSource = self

TableView Items get refresh on scrolling

Having UICollectionView as a child of UITableView row. UICollectionView contains images, but whenever I scroll tableview down and up the collection view images got vanished randomly. I am attaching images for my problem reference. Please suggest me how to stop this.
I want my tableview to be like this. And its items should not change on scrolling.
----------------------------------------------------------------------------------------------------------------------------------------------
The collectionview images got vanish on scrolling tableview. It looks like this after scrolling up.
Code Is as follow:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell:PartOfLookTableViewCell = self.looksListTable.dequeueReusableCell(withIdentifier: "cell") as! PartOfLookTableViewCell
let oneRecord = looksArray[indexPath.row]
cell.myCollectionView.loadInitial(_dataArray: oneRecord.imagesArray, isLooks: 1)
return cell
}
Code for loading data to CollectionView:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: looksReuseIdentifier, for: indexPath) as! CustomCollectionViewCell
let oneRecord = inputArray[indexPath.row]
cell.productImage.sd_setImage(with: URL.init(string: oneRecord.thumb_url)){ (image, error, cacheType, url) in
DispatchQueue.main.async {
cell.productImage.image = image
}
}
}
}
}
#Sourabh Bissa :
UITableView reuses the cell using method CellForRowAtIndexPath whenever your new cell gets visible your this method reuse the data source.
The very important thing here is to maintain the data source:
In your case cell for the row at index path giving the updated value to the collection view method but you are not reloading in main Queue. Try to do it immediately after you get the data source.
Your Cell for the row at index path will look like this :
guard let cell = self.tableview.dequeueReusableCell(withIdentifier: "cell") as! PartOfLookTableViewCell else {
return UITableViewCell()
}
let oneRecord = looksArray[indexPath.row]
cell.configureCell(for record : oneRecord with looks : 1)
return cell
and Now in the cell, you will have collection view outlet, where you will implement a collection view data source method and there you download your images asynchronously.
Cell Class will look like this :
class PartOfLookTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func configureCell(for record : Record , with looks : Int) {
// Here reload your collection view
// This collection view will be specific to the cell.
collectionView.reloadData()
}
}
extension PartOfLookTableViewCell : UICollectionViewDelegate , UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return array
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Asyncronously download images
}
}
This is how you can achieve your requirements without using any tags. Please let me know if you have any Queries in it.

Resources