Swift Reload CollectionView in Tableview Header with Xib - ios

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

Related

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
}

Updating collection view items

I have inserted a collectionView inside my tableViewCell. Tableview contains the list of categories and the collectionView contains all the product. How can I have a different number of items in the collectionView based off of which table view row was selected? I've tried storing the selected table view row and using that to define the number of items to be returned however it either crashes with no error code, tells me the value is nil or just does not display any clitems in the collectionView. Any help would be greatly appreciated. Thank you for your time.
Below is my code:
My Custom table view cell:
extension ExpandableCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let toReturn = categoryItems.count
return counter
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CustomCollectionViewCell
//What is this CustomCollectionCell? Create a CustomCell with SubClass of UICollectionViewCell
//Load images w.r.t IndexPath
print(self.selectedCategory.description)
let newArray = starbucksMenu[selectedCategory]
//cell.image.image = UIImage(named: (allItems[selectedCategory]?[indexPath.row])!)
cell.label.text = categoryItems[indexPath.row]
//cell.layer.borderWidth = 0.1
return cell
}
My table view delegate method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
word = indexPath.row
guard let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell
else { return }
switch cell.isExpanded
{
case true:
self.expandedRows.remove(indexPath.row)
self.selectedCategory = ""
case false:
self.expandedRows.insert(indexPath.row)
}
self.selectedCategory = categories[indexPath.row]
print(self.selectedCategory)
//self.array = starbucksMenu[starbucksMenuCategories[indexPath.row]]!
//self.collectionView.reloadData()
cell.menuItems = allItems[selectedCategory]!
cell.categoryItems = allItems[selectedCategory]!
cell.isExpanded = !cell.isExpanded
self.itemsArray = allItems[selectedCategory]!
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
I've tried many things, I've tried adding the items in an array and returning the count (displays nothing). I have a dictionary with the necessary items so I've also tried returning allItems[selectedCategory]?.count and this always returns an error, I believe selectedCategory has no value once this is called.
Make a for loop of collection view item with appropriate operation Between beginUpdate() and endUpdate()

Self Sizing CollectionViewCell

I try to make my collectionView Cell height as per content.
I tried with Self Sizing CollectionViewCell but it is not working.
I used auto layout in CollectionView Cell.
Cell have three Labels with top,left,bottom,right Constraints & have Vertical Compression Ration is Required(1000).
My code is as follow:
override func viewDidLoad() {
super.viewDidLoad()
let flowlayout = col.collectionViewLayout as! UICollectionViewFlowLayout
flowlayout.estimatedItemSize = CGSizeMake((self.view.frame.size.width - 60) / 2 , 1)
}
}
//MARK: CollectionView
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 17
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = col.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
if indexPath.row == 0 {
cell.lbl1.text = "Lorem ispum Simple text to show if it working or not"
}
else{
cell.lbl1.text = "\(indexPath.row)"
}
return cell
}
Some People are saying that it is not possible for collectionView Self Sizing Cell, even though Apple claims it.
You have to calculate manually.
If I try to calculate it manually then I am also unable to get cell object in sizeForItemIndexPath

collectionview cell for xib not showing

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.

Resources