embed custom view into UITableViewCell - ios

I already have a subclass of UIView, called CustomView, which I use in stack views.
I am wanting to redo the UI and use a table view instead. So, for that I just wanted to reuse the CustomView class I already have but for some reason the table view is not showing the cell at all.
I think the issue is the way I am using CustomView in CustomCell: UITableViewCell:
class CustomCell: UITableViewCell {
#IBOutlet var customView: CustomView!
}
in the view controller holding the table view, I have in viewDidLoad:
tableView.register(UINib(nibName: "CustomCell", bundle: Bundle.main), forCellReuseIdentifier: "CustomCell")
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
When I run the app, I just get a blank table view.

Good day I made the same code that you, and works , could you add breakpoint in this position.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath)
}
you shouldn't have problem using custom views inside cells.

You have to use designated initializer for your custom view like init(frame:CGRect) or add it to the interface builder, like a prototype cell.

Related

Adding label to a prototype cell

I need to add a label to a prototype cell but I am getting the error "Value of type 'UITableViewCell' has no member 'movieTitleLabel'.
import UIKit
class FirstTableView: UITableViewController {
let model = MovieModel()
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return model.MovieArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCells", for: indexPath) as! TableViewCell
cell.movieTitleLabel?.text = model.movieArray[indexPath.row]
return cell
}
I have the FirstTableView set as the delegate and datasource, in the editor.
I created a new subclass named: TableViewCell, linked the label to that class. Now I am at at loss as to how to output the movieArray to that label.
You forgot to downcast cell to your UITableViewCell subclass so you have reference just to superclass UITableVoewCell and this superclass hasn’t any movieTitleLabel.
To fix this, add as! YourTableViewCellSubclass to the end of the line where you dequeue cell
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCells", for: indexPath) as! YourTableViewCellSubclass
Look out into these points:
You have created an outlet of the label named as 'movieTitleLabel' in ViewController, but this label should be in TableCell class. Make correct reference of this label.
After the first point, now to access this label, follow this code:
Code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableCellIdentifier", for: indexPath) as! YourTableCellClass
cell.movieTitleLabel.text = "Text" // Set your text here now
return cell
}
Your prototype cell should have specified an implementation class - this must be a subclass of UITableViewCell. If you've done this, downcast the result of dequeueReusableCell to this class.
You should also have connected the movieTitleLabel outlet in that class to the label in the storyboard. It looks from the above as if you've connected it to the UITableViewController instead (#IBOutlet weak var movieTitleLabel: UILabel!). You should remove this from the VC and only have it in the UITableViewCell class.

Why is my tableView not being populated?

I'm trying to populate a basic tableview with sample data in code. Here's my ViewController:
import UIKit
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var postTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath)
cell.textLabel?.text = "title"
cell.detailTextLabel?.text = "detail"
return cell
}
}
Here is my storyboard
I'm sure that the name "postcell" is correct and that I've hooked up the tableView to the ViewController as a datasource and delegate.
When I run the code in the iOS simulator, no cells show up. This is what I see:
Here are the constraints on my stack view
stack view properties
I don't want to use UITableViewController
How do I get the table cells to appear?
If "postcell" is not a prototype cell from your storyboard, you need to register it in your viewDidLoad:
postTableView.register(UITableViewCell.self, forCellReuseIdentifier: "postcell")
If it is a XIB table view cell you would register it as follows:
postTableView.register(UINib(nibName: "NibName", bundle: nil), forCellReuseIdentifier: "postcell")
If you were to do it from storyboard, drag a prototype cell (or table view cell) onto your table view and in the reuse identifier call it "postcell" as shown here:
Make sure you have also done the following in your viewDidLoad:
postTableView.delegate = self
postTableView.dataSource = self
Of course, you'll also need:
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath) as postcell // add this line
Thank you #MrSaturn for pointing out in the comments that it's a problem with the stack view. In storyboard I had to change the stack view's alignment property from center to Fill.

is there a callback method that tells when a UITableViewController has finished creating the cells of a UITableView?

Is there an iOS / Swift 3.0 callback method that tells when a UITableViewController has finished loading (creating the cells of) a UITableView (after calling the .reloadData on the table view (in Swift)?
(or alternative method)
The func you're looking for doesn't exist, but per your comment above, would it be possible to get each cell (or some model object it takes as a property) to make the API pre-load call? In this way, data will only be pre-loaded for visible cells. When new cells are scrolled into view, their data will be loaded in turn.
For example, in your cell:
class MyCell: UITableViewCell {
var someObject: MyObject {
didSet {
someObject?.loadData()
}
}
}
and in your view controller:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! "MyCell"
cell.someObject = myObjects[indexPath.row]
return cell
}
This way you're only loading data for cells in view. If you were to add:
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.someObject.cancelLoading()
}
You can ensure that objects in cells no longer view aren't loaded if not required.

implementing UITextFieldDelegate

I want to use https://github.com/intuit/AnimatedFormFieldTableViewCell in my project but I can’t get my head around the steps for setting it up. So far, I’ve dragged the files from the folder and followed the steps as:
In order to use AnimatedFormFieldTableViewCell, all you have to do is:
1) Register the AnimatedFormFieldTableViewCell nib on the ViewController on which you are implementing your UITableView for your reuse identifier.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerCellNib(AnimatedFormFieldTableViewCell)
tableView.reloadData()
}
2) Dequeue your cell on CellForRowAtIndexPath as a AnimatedFormFieldTableViewCell.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! AnimatedFormFieldTableViewCell
return cell
}
3) Change the placeholder's label text by calling setLabelText on the cell itself.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! AnimatedFormFieldTableViewCell
cell.setLabelText("Enter title")
return cell
}
Notes:
1) You can still implement UITextFieldDelegate the same way you would implement on a regular UITextField, you just need to define the AnimatedFormFieldTableViewCell's delegate (there is no need to directly define the delegate for the embedded UITextField).
2) In order to access the embedded UITextField you can simply call the cell's cellTextField property.
I don’t get these last two steps.
If I run my app, I get the unexpectedly found nil on self.cellTextfield.delegate = self in the AnimatedFormFieldTableViewCell class.
What am I missing?
Hi waseefakhtar your code does not miss anything. just the only problem is you registered the nib with the wrong way that's why you got the unexpectedly found nil error on self.cellTextfield.delegate = self.
try this code:
let myNib = UINib.init(nibName: "AnimatedFormFieldTableViewCell", bundle: nil)
self.tableView.registerNib(myNib, forCellReuseIdentifier: "cell")
PS: just be aware that registerNib method syntax can differ depending on the swift version
My code is here, I don't know where you clerical error, but you can check my code to find out:
import UIKit
class ViewController2: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// register a nib like below
let nib:UINib = UINib.init(nibName: "AnimatedFormFieldTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier: "AnimatedFormFieldTableViewCell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 88.0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AnimatedFormFieldTableViewCell", for: indexPath as IndexPath) as! AnimatedFormFieldTableViewCell
cell.setLabelText("Enter title")
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
The result:
So, just check the steps, where you go wrong.
The documentation notes this:
There is no need to directly define the delegate for the embedded UITextField
The instruction is to do the following:
You just need to define the AnimatedFormFieldTableViewCell's delegate
You'll want to set the AnimatedFormFieldTableViewCell's delegate rather than the cellTextField's delegate, so:
self.delegate = yourUITextViewDelegate
rather than self.cellTextField.delegate = yourUITextViewDelegate (this is wrong)
This is what the documentation describes
Edit: OP clarified that the delegate assignment code is not in their class; it's in the pod's class. I'm considering deleting this answer as I don't think it is solving the problem.

UITableViewCell basic style on Storyboard can't select

I have strange behavior with UITableView on Storyboard today. I have created UITableView on Storyboard. After that I drag a PrototyleCell to this table and choose style is Basic. And I implement DataSource and Delegate on my ViewController. It show to simulator normal. But I can't tap to table for select a cell and didSelectCellAtIndexPath don't work too. In Storyboard I have checked selectionStyle. If I change style to another style, It work normally.
So my question is: this is a bug or it is a behavior of UITableView? And anyone can give some explanation for it.
Here is my code: Problem Cell Code. I can't select when use it but when I set another style of cell on storyboard everything will ok.
Thanks in advance
No its neither bug nor normal behavior, you must be doing some basic mistake...
Try following code with tableview and prototype cell in storyboard, Everthing will work.
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataSource = ["Ajay","Ajay","Ajay","Ajay","Ajay","Ajay"]
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell?
if cell == nil {
cell = UITableViewCell(style: .Value1, reuseIdentifier: "cell")
}
cell!.textLabel?.text = dataSource[indexPath.row]
return cell!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print(indexPath.row)
} }
Have you added the
tableView: cellForRowAtIndexPath delegate method. This is a required delegate you must implement.

Resources