UICollectionView inside TableView not populating cells? - ios

I have a tableView with rows that need to be horizontally flowing collectionViews.
My tableView cells have a single collectionView within them, and then I instantiate them like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: MyTableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTableViewCell", forIndexPath: indexPath) as! MyTableViewCell
let nibName = UINib(nibName: "CollectionCell", bundle: nil)
cell.collectionView.registerNib(nibName, forCellWithReuseIdentifier: "CollectionCell")
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
return cell
}
I'm trying to use an auto-height table view row, and I think this is what could be causing issues. How do I use UITableViewAutomaticDimension with internal collection views?

This is in objective-c, but works for me:
i. In your custom cell's .m file register the UICollectionViewCell nib, and specify you layout details (size, spacing etc.).
ii. in the VC that holds the tableView its .m do the following in cellForRowAtIndexPath
MyTableViewCell *cell = (MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:#"MyTableViewCellId" forIndexPath:indexPath];
cell.collectionView.delegate = self;
cell.collectionView.dataSource = self;
cell.collectionView.tag = indexPath.row;
[cell.collectionView reloadData];
iii. You can use the tag of the UICollectionView in the delegate methods to populate the right information
Hop this helps.

Try adding - cell.setTranslatesAutoresizingMaskIntoConstraints(false) - see below
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: MyTableViewCell = tableView.dequeueReusableCellWithIdentifier("MyTableViewCell", forIndexPath: indexPath) as! MyTableViewCell
let nibName = UINib(nibName: "CollectionCell", bundle: nil)
cell.collectionView.registerNib(nibName, forCellWithReuseIdentifier: "CollectionCell")
cell.collectionView.dataSource = self
cell.collectionView.delegate = self
cell.setTranslatesAutoresizingMaskIntoConstraints(false)
return cell
}
See https://www.captechconsulting.com/blogs/ios-8-tutorial-series-auto-sizing-table-cells for some more information.

Related

Why is custom UICollectionViewCell's outlet nil after scroll?

I wrote a custom component that uses UICollectionView and this UICollectionView has also custom UICollectionViewCell class with xib file.
In my UIViewController class viewDidLoad method, I send a web service request and after the response comes I register my custom UICollectionViewCell with this code;
let bundle = Bundle(for: MyCustomCellClass.self)
let nib = UINib(nibName: "MyCustomCellClass", bundle: bundle)
collectionView.register(nib, forCellWithReuseIdentifier: MyCustomCellClass.reuseIdentifier)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.reloadData()
Then in my UICollectionView cellForItemAt I dequeue cell with this way;
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCustomCellClass.reuseIdentifier, for: indexPath) as? MyCustomCellClass else {
fatalError("Cell should be registered")
}
let carObject = myList![indexPath.row])!
cell.carImageView.image = carObject.image
return cell
}
The problem exists after I scroll, the car image has gone. That is because my MyCustomCellClass image view outlet becomes suddenly nil.
I can't find the solution, any help would be greatly appreciated.

How to connect custom collectionviewCell to reuseidentifier with XIB - Swift

I am making a custom collectionview cell Using XIB.
The collectionview is placed inside an viewController as an extension.
This is the code i am using to call the Xib View but i get an error telling me i need to use reuseidentifier. But i have no clue how to use that while using XIB.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = Bundle.main.loadNibNamed("CustomCell", owner: self, options: nil)?.first as! CustomCell
return cell
}
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:'
*** First throw call stack:
First you need to create a reuseIdentifier for your cell. Lets create it based on your collectionViewCell class name. Declare reuseId, in your ViewController file:
let reuseId = String(describing: CustomCell.self)
You need to register your cell to your collectionView in viewDidLoad method.
collectionView.register(CustomCell.self, forCellReuseIdentifier: reuseId)
Then in your cellForItemAt method:
guard let cell = collectionView.dequeueReusableCell(withIdentifier: reuseId, for: indexPath) as? CustomCell else { return UICollectionViewCell() }
//return cell, or update cell elements first.
You can register the CustomCell like,
let customCellNib = UINib(nibName: "CustomCell", bundle: .main)
collectionView.register(customCellNib, forCellWithReuseIdentifier: "CustomCell")
And use the same registered cell in cellForItemAt like,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier:"CustomCell", for: indexPath) as? CustomCell else {
return UICollectionViewCell()
}
return cell
}
For Swift 4.0 and 4.2
In your viewDidLoad:
custom collectionViewCell
mainCollectionView.register(UINib(nibName: "your_custom_cell_name", bundle: nil), forCellWithReuseIdentifier: "your_custom_cell_identifier")
In cellForItemAt indexPath:
let cell : <your_custom_cell_name> = mainCollectionView.dequeueReusableCell(withReuseIdentifier: "your_custom_cell_identifier", for: indexPath) as! <your_custom_cell_name>
And don't forget to set identifier for your custom cell in xib section.

Including nib file for custom UIView in CellForRowAt producing jerk while scrolling

I have a UITableView and I am including a nib file of my custom UIView in a "CellForRowAt" delegate function of tableView which is producing jerk while scrolling. For Example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"cell", for: indexPath) as! CustomCell
let customView: CustomView = Bundle.main.loadNibNamed("CustomView", owner:
self, options: nil)![0] as! customView
cell.customViewPlacement.addSubview(customView)
return cell
}
How can I fix the scrolling and what is the issue in my code?
Thanks
cell.customViewPlacement.addSubview(customView)
This is not how you create cell and reuse in your cellForRow, you are basically create new view and add it everytime your cell scroll (keep making duplicated), thus make it jerking, you have to create your cell nib with that view, and register your nib file in viewDidLoad like:
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
and in cellForRow just dequeue like normal:
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
If you have many different kind of cell, make multiple cells class, not make new view and add to current cell

How do I embed a UITableView in a UIView?

I have a UIView in a custom view that I built using xib. I need to display a UITableView in the said view. At first I thought about placing a container and embedding a UITableViewController in it. Turns out I cannot place containers in a xib file, or atleast there's no way of doing it from the IB as it doesn't show up in views section at the lower right.
I can create a UITableView programmatically and add it as a subview of the view. It shows up as expected but I cannot seem to be able to add cells in it. I also tried creating a well behaving UITableViewController in association with a storyboard view, instantiate that controller as follows:
let storyboard = (UIStoryboard(name: "Main", bundle: nil))
let vc = storyboard.instantiateViewControllerWithIdentifier("tableViewController") as! TestTableViewController
and then tried accessing the UITableView's outlet which was nil. Then I read somewhere that I should do a vc.loadView() because as the name suggests, it loads the view and my IBOutlet would not be nil. This worked. The outlet was on longer nil. But, when I add the table in the container view as a subview, it still shows no cells. There are only separator lines but no content. I've run out of ideas!
EDIT
I do not have any UITableViewCell implementations as the tables are static.
Good approach is to use UITableview inside your custom view:
if you are adding tableview programmatically then register your cell using Nib or UITableview subclass like
tableView.registerNib(UINib(nibName: "UITableViewCellSubclass", bundle: nil), forCellReuseIdentifier: "UITableViewCellSubclass")
for if you are creating UITableviewCell using Xib.
tableView.registerClass(UITableViewCellSubclass.self, forCellReuseIdentifier: "UITableViewCellSubclass") // using code.
tableView.delegate = self
tableView.dataSource = self
and then use 2 required delegates.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return tableView.dequeueReusableCellWithIdentifier("UITableViewCellSubclass", forIndexPath: indexPath) as! UITableViewCellSubclass
}
hope i answered your question.
Objective c
You need delegates in your viewcontroller, if you have a viewcontroller, put delegate of table :
UIViewController
UITableViewDelegate
UITableViewDataSource
And you can use your functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1; //count of section
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [catagorry count]; //count number of row from counting array hear cataGorry is An Array
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the provided setImageWithURL: method to load the web image
// Ensure you use a placeholder image otherwise cells will be initialized with no image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
cell.textLabel.text = #"My Text";
return cell;
}
Swift :
delegate:
UIViewController
UITableViewDataSource
UITableViewDelegate
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
Swift
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let row = indexPath.row
cell.textLabel?.text = swiftBlogs[row]
return cell
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(textCellIdentifier, forIndexPath: indexPath)
let row = indexPath.row
cell.textLabel?.text = swiftBlogs[row]
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return swiftBlogs.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
Look more More inf

How to correctly implement a table view with a fixed number of custom cells?

I have a UITableView I need to have just 3 cells. This is what I have in IB: . All cells contain a UITextField, and that's why are using custom cells. Each cell is binded to a CustomCell class with the corresponding UITextField as an outlet. I also have protocols to pass the texts in the UItexField to the table's UIViewController.
In the UIViewController I have this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
switch indexPath.row {
case 0:
cell = tableView.dequeueReusableCell(withIdentifier: "firstNameCell", for: indexPath)
(cell as! FirstNameTableViewCell).delegate = self
case 1:
cell = tableView.dequeueReusableCell(withIdentifier: "lastNameCell", for: indexPath)
(cell as! LastNameTableViewCell).delegate = self
case 2:
cell = tableView.dequeueReusableCell(withIdentifier: "birthdateCell", for: indexPath)
(cell as! BirthdateTableViewCell).delegate = self
default:
break
}
return cell
}
But here:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(FirstNameTableViewCell.self, forCellReuseIdentifier: "firstNameCell")
tableView.register(LastNameTableViewCell.self, forCellReuseIdentifier: "lastNameCell")
tableView.register(BirthdateTableViewCell.self, forCellReuseIdentifier: "birthdateCell")
}
The contents of the cells are not shown.
Which is the correct way to deal with this scenario?
As Sandeep Bhandari said, if you want to keep static cells, then use static cells in tableview:
You can specify number of rows, sections, and number of rows in each sections etc. there in storyboard itself.

Resources