Currently, I have two table view controllers which contain some identical custom tableview cells. Each table view controller has its own custom tableview cells. I'm wishing to create only one custom table view cell which can be shared among these two table view controllers. Any guides can I refer to?
First you can create a UITableViewCell with code: (and you can design your cell view in a .xib file - see here for detail)
// MyCell.Swift
import UIKit
import Foundation
class MyCell: UITableViewCell {
// do whatever you want to customize the cell
}
Then in each of your two UITableViewController's classes, register your custom UITableViewCell class in viewDidLoad.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(MyCell.self as AnyClass, forCellReuseIdentifier: "cell")
}
Then create/reuse this custom cell in cellForRowAtIndexPath function:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: MyCell? = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCell
if cell == nil {
// if the cell is not yet created in the system, create a new cell object
cell = MyCell(style: .default, reuseIdentifier: "cell")
}
// customize your cell...
cell.textLabel?.text = "Your Label Text"
return cell!
}
Related
I have created xib file which is sort of a template to the different table view cells I will be having. The xib has a left label and a button on the right. The actions will be different when button is clicked, so I created a .swift file for the xib which has outlets connected to it and then I created 2 sub-classes out of the .swift file which will basically set the target on button and perform different actions. However this doesn't work and the controls are not showing up on the app.
Custom xib file and base swift class for the xib:
Sub-class from LeftLabelRightButton swift class:
Registering xib in view controller and cell for row at index path:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "LeftLabelRightButton", bundle: nil), forCellReuseIdentifier: "myCell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as? SampleSubClass {
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.leftLabel.text = "Hello World"
cell.leftLabel.textAlignment = .left
}
}
I am not getting any errors with this, but I don't see the label or the button if I dequeue the cell as SampleSubClass.
If I do this then I see the label and button on the app:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as? LeftLabelRightButton {
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.leftLabel.text = "Hello World"
cell.leftLabel.textAlignment = .left
}
}
Can I dequeue the cell as sub-class? Does the outlet get inherited? My guess is with sub-class the outlets are not getting inherited.
First question : Yes. You can reuse xib across the app. Just register it to your UITableView or UICollectionView.
Second one : Yes also, but you can't use dequeueReusableCell. So i think it's useless.
I have a UITableViewController and want to populate it with custom cells. The cell I have created has it's own class and xib file, away from the main storyboard.
In the xib file, I have 'VisitCell' as the identifier.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "VisitCell", for: indexPath) as! VisitCell
let visit : BookingVisitItem = bookingDayItem.getVisitItems()[indexPath.row]
cell.locationLabel?.text = visit.getVenueName()
cell.timeLabel?.text = visit.getVisitTime()
cell.typeLabel?.text = visit.getVisitType()
return cell
}
If I run the code like this, it seems to crash. Maybe it can't find the custom cell?
However, if I add the following to viewDidLoad()
tableView.register(VisitCell.self, forCellReuseIdentifier: "VisitCell")
At this stage, it doesn't crash but the table view appears to be empty.
Any pointers? Thanks!
Register your nib cell in viewDidLoad()-:
override func viewDidLoad() {
super.viewDidLoad()
yourTableView.registerNib(UINib(nibName: "yourcell", bundle: nil), forCellReuseIdentifier: "CustomCellOne")
}
I need to add cell identifier to make ReusableCell for tableView. However I don't see any cell in the tableView properties and table view hierarchical. how to add a cell in the table view .
note : basically i want to create a Xib file which should contain a tableView and that tableView should have custom UiTableViewCell
code here :
class SuggestNearTableViewCollectionViewCell: UICollectionViewCell , UITableViewDataSource,UITableViewDelegate{
#IBOutlet weak var suggestTableView : UITableView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.suggestTableView.dataSource = self
self.suggestTableView.delegate = self
suggestTableView.register(UINib(nibName: "SuggestNearTableViewCell", bundle: nil), forCellReuseIdentifier: "SuggestNearTableViewCell")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SuggestNearTableViewCell", for: indexPath) as! SuggestNearTableViewCell
return cell
}
}
First of all go to File-> new -> Cocoa Touch Class and create class of UIViewCOntroller. Name your class accordingly.
Now you will have a Xib file and a Swift file. Xib would look something like this.
Now drag and drop a UITableView on the Xib and give it 4-pin constraints as top=0, bottom=0, leadin=0, and trailing=0. Now create an outlet of your tableView in your newly created swift file. Connect data Source and delegate as well.
Now again go to File->New-> Coucoa Touch Class and create a class for UItableViewCell also create a Xib file like below.
Now you will have a Xib for your cell and a swift file for your cell. Just design your cell as your need in this Xib. Lets say If you want to put an imageView or a label etc. Then create outlets of all components in swift file of your custom cell. Now add this function in swift file of your custom cell.
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.registerNib(UINib(nibName: "YourCustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCellWithIdentifier(kYourCustomTableViewCellIdentifier, forIndexPath: indexPath) as! YourCustomTableViewCell
return cell
}
Your custom cell is ready to use.
Now go to the swift file of your tableView and in your cellForRowAtIndexPath just use use this cell like below.
let cell = YourCustomTableViewCell.cellForTableView(tableView, atIndexPath: indexPath)
cell.myImageView.image = "something"
// Do something with your cell
I hope it would be helpfull. Let me know if you find any difficulty.
Inside tableViewController in viewDidLoad you should register it like this:
tableView.registerNib(UINib(nibName: "CustomOneCell", bundle: nil), forCellReuseIdentifier: "CustomCellOne")
And inside cellForRowAtIndexPath just declare cell:
let cell: CustomOneCell = tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell
If you are not doing it inside tableViewController then you gotta connect your tableView and delegate:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
...
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Table view delegate
self.tableView.delegate = self
self.tableView.dataSource = self
...
I have created a component in XIB file. This file includes 2 components
Label
TableView
I have then linked and set it's File's Owner class to SampleView. I have attached the XIB file view with SampleView.swift file and this file have only following code in it's class:
#IBOutlet var view: UIView!
I have now created a controller file SampleController with protocols UIViewController, UITableViewDelegate and UITableViewDataSource. I have placed the following code in it's init() func to display the custom component:
init() {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = UIModalPresentationStyle.Custom
view.addSubview(SampleView())
}
I am using this SampleController to programmatically display as a Modal.
These codes does display as the Modal showing Label and TableView. It also populates the data in TableView. The problem is:
When I tap the cell in table, it doesn't trigger the event on first attempt. When I tap another cell then it trigger the previous cell event.
Any idea why is this happening?
Here are 2 functions used for populating and handling cell tap:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CELL")
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CELL")
}
cell!.textLabel?.text = sampleData[indexPath.row]["title"]
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
print("tapped")
}
Darn it! I was using didDeselectRowAtIndexPath instead of didSelectRowAtIndexPath. That's what will happen when you are programming after midnight.
You need to use a different method to dequeue the cell:
var cell = tableView.dequeueReusableCellWithIdentifier("CELL", forIndexPath: indexPath)
The check for a nil cell is unnecessary, by the way.
I am working on a IOS Swift based project that uses a few classes to customize the UITableView and the UITableViewCell. Now one of my Cells inside the UITableView has an inner UITableView. I was wondering if it is possible when inside the cellForRowAtIndexPath, that I could also populate cells programmatically in that same process.
EX:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomTableViewCell
...... do stuff
cell.detailview.uitableview <!-- populate the cells here?
.......
return cell
}
Suggestions?
Assuming three different types of cells:
class NormalTableViewCell: UITableViewCell: This is used for the "regular" cells of your outer (main) table view.
class TableContainingTableviewCell : UITableViewCell: This is used for the "special" cells of your outer (main) table view, that contain a table view (inner) within themselves.
class InnerTableViewCell : UITableViewCell: This is used for the cells of your inner table views (those contained in cells of class TableContainingTableviewCell).
(Replace each by your actual class names).
, you can use this code:
override func viewDidLoad()
{
super.viewDidLoad()
// This can also be done in storyboard with prototype cells:
self.tableView.registerClass(NormalTableViewCell.class, forCellReuseIdentifier: normalCellIdentifier)
self.tableView.registerClass(TableContainingTableViewCell.class, forCellReuseIdentifier: specialCellIdentifier)
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath
) -> UITableViewCell
{
if tableView == self.tableView {
// [A] OUTER TABLE VIEW
if indexPath == index path of table-containing cell {
// (A.1) TABLE-CONTAINING CELL
let cell = tableView.dequeueReusableCellWithIdentifier(specialCellIdentifier, forIndexPath: indexPath) as! TableContainingTableViewCell
// (...configure cell...)
// Setup and refresh inner table view:
cell.contentView.tableView.dataSource = self
// This is needed for dequeueing to succeed:
cell.contentView.tableView.registerClass(InnerTableViewCell.class, forCellReuseIdentifier: innerCellIdentifier)
cell.contentView.tableView.reloadData()
// ^ THIS TRIGGERS A CALL TO THIS FUNCTION, ON THE
// INNER TABLE VIEW (PATH [B] BELOW)
return cell
}
else {
// (A.2) NORMAL CELL
let cell = tableView.dequeueReusableCellWithIdentifier(normalCellIdentifier, forIndexPath: indexPath) as! NormalTableViewCell
// (configure cell)
return cell
}
}
else {
// [B] INNER TABLE VIEW
let cell = tableView.dequeueReusableCellWithIdentifier(innerCellIdentifier, forIndexPath: indexPath) as! InnerTableViewCell
// (configure cell)
return cell
}
}
...but I would strongly argue against having a table view embedded inside a another table view's cell. At the very least, make sure the inner table view does not need to scroll (i.e., the containing cell is high enough to show all rows and the table itself has scroll disabled).