I want to make a custom UITableViewCell that can have many columns. One will be a UILabel and one will be a UIButton. I want to start this off by saying I only create my IBOutlets by holding the control key and dragging the UI items to my code. So this means all of my IBOutlets are connected properly. My problem is that the UILabel and the UIButton are not visible in any of my cells. The cells are there, but nothing else.
class CustomTableViewCell: UITableViewCell{
#IBOutlet weak var label: UILabel!
#IBOutlet weak var button: UIButton!
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var items: [Strings] = ["one", "two", "three"]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad(){
super.viewDidLoad()
self.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:CustomTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cell")! as! CustomTableViewCell
cell.label?.text = self.items[indexPath.row]
return cell
}
}
I have the UITableView's data source and delegate set to the ViewController, I have the cell reuse id set up properly and both the UILabel and UIButton have constraints set up. I feel like I am missing something.
You must not register the cell – when using prototype cells – but you must reload the table view.
Replace
override func viewDidLoad(){
super.viewDidLoad()
self.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "cell")
}
with
override func viewDidLoad(){
super.viewDidLoad()
self.tableView.reloadData()
}
Those are missing:
self.tableView.delegate = self
self.tableview.datasource = self
Hope this helps!
Related
Overview
I'm trying to better understand how extensions work.
In my app I have a ViewController. There I put a view of another class. In this custom class I put a bunch of buttons and a table view. I want them to display some text inside of my tableView whenever I press them.
The problem is that I want to edit some of the table view functions in order to better adjust it to my ViewController.
What I know
All I know is based on the apple documentation
What I'm doing
What I'm trying to do, I should say, is to add functionality to a custom view's function after adding an object which is of the type of my custom class to the ViewController.
This is my custom class:
class CustomClass: UIView{
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("I want to add stuff here too")
}
//And more stuff that is not useful rn
}
Inside of the ViewController class I have declared a variable of type CustomClass.
#IBOutlet weak var custom: CustomClass!
In my viewDidLoad I call :
custom.setupTable()
What I need to do is creating an extension to edit the tableview that belongs to custom (the variable of type CustomClass that is inside of my ViewController).
I have no clue on how to do that.
I know how to work with extension to expand my code's functionality but I don't know how to use them to edit these other functions.
Question
How do I edit the tableview functions that belong to custom?
Ie. how would I be able to change the number of rows or to change the cell's layout from the class I call the object in?
I hope I was clear enough...
For this specific example...
Add a property to your CustomClass:
class CustomClass: UIView {
// this may be changed by the "calling class"
var numRows: Int = 10
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
In your extension, use that property:
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// don't make this a hard-coded number
//return 10
return numRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
//And more stuff that is not useful rn
}
Then, in your "calling class", you can change that property:
class ExampleViewController: UIViewController {
let myView = CustomClass()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myView)
// constraints, etc
// change the number of rows in the table in myView
myView.numRows = 20
}
}
More likely, though, you would be doing something like setting / changing the data for the table in your custom class.
Here's an example, along with showing how to use a closure to "call back" to the calling class / controller:
class CustomClass: UIView {
// this may be changed by the "calling class"
var theData: [String] = []
// closure to "call back" to the controller
var callback: ((IndexPath) -> ())?
#IBOutlet weak var abtn: UIButton!
#IBOutlet weak var table: UITableView!
func setupTable(){
table.delegate = self
table.dataSource = self
table.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
table.backgroundColor = UIColor.black.withAlphaComponent(0.1)
}
}
extension CustomClass: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
cell.textLabel?.text = theData[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// tell the controller the cell was selected
callback?(indexPath)
}
}
class ExampleViewController: UIViewController {
let myView = CustomClass()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(myView)
// constraints, etc
// set the data in CustomClass
myView.theData = [
"First row",
"Second row",
"Third",
"Fourth",
"etc..."
]
myView.callback = { indexPath in
print("CustomClass myView told me \(indexPath) was selected!")
// do what you want
}
}
}
I have a strange issue with attempting to get my custom table view cell to display. It seems logically correct. It follows the Apple Documentation logic and about every site's exact logic, yet it won't display. Is there something I', missing?
class FavTableCell: UITableViewCell{
#IBOutlet weak var Testo : UILabel!
#IBOutlet weak var TestoBackgoundImage : UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
override func prepareForReuse() {
super.prepareForReuse()
// any extra code or logic here
}
}
class TableViewClass : UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
TableView.delegate = self
TableView.dataSource = self
TableView.register(CustomTableCell.self, forCellReuseIdentifier: "Table")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let TableCell = tableView.dequeueReusableCell(withIdentifier: "Table", for: indexPath) as! CustomTableCell
TableCell.TestoBackgoundImage?.image = Image Literal// image literal here
TableCell.Testo?.text = self.TableArray[indexPath.row]
return TableCell
}
}
If you have created it as a prototype cell ( design is inside the table itself ) then remove
tableView.register(CustomTableCell.self, forCellReuseIdentifier: "Table")
if it's an xib then do
tableView.register(UINib(nibName: "CustomTableCell", bundle: nil), forCellReuseIdentifier: "Table")
I have a UICollection view that has two custom cells. The UICollectionViewCell custom cells are built using NIB's. Inside one of the UICollectionViewCell NIB's, I have a UITableView. However, the UITableView itself has custom cells. So my question is:
How do I load a custom cell for the UITableView instead a UICollectionViewCell NIB?
import UIKit
class HeaderFooterCollectionViewCell: UICollectionViewCell {
//Tableview
#IBOutlet weak var tableView: UITableView!
//Buttons
#IBOutlet weak var resetButton: UIButton!
#IBOutlet weak var periodButton: UIButton!
#IBOutlet weak var undoButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// Register cell classes
tableView.register(UINib(nibName: "ShotInformationTableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
}
}
extension HeaderFooterCollectionViewCell: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ShotInformationTableViewCell
return cell
}
}
let cell = Bundle.main.loadNibNamed("XIB_File_Name", owner: self, options: nil)?.first as! XIB_Class_Name
In almost all cases , XIB_File_Name == XIB_Class_Name
I am working on a todo list app that works with a table view in Swift. The table view has a UILabel called titleLabelOutlet. When I was building the app I got an error that says The titleLabelOutlet outlet from the FirstViewController to the UILabel is invalid. Outlets cannot be connected to repeating content.I have never received this error before. How do I fix it? This is my code:
import UIKit
var phoneNumberList = [String]()
var titleFieldList = [String]()
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var titleLabelOutlet: UILabel!
#IBOutlet weak var phoneNumberLabelOutlet: UILabel!
#IBOutlet weak var myTableView: UITableView!
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return (phoneNumberList.count)
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
phoneNumberLabelOutlet.text = phoneNumberList[indexPath.row]
titleLabelOutlet.text = titleFieldList[indexPath.row]
return(cell)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath)
{
if editingStyle == UITableViewCellEditingStyle.delete
{
phoneNumberList.remove(at: indexPath.row)
titleFieldList.remove(at: indexPath.row)
myTableView.reloadData()
}
}
override func viewDidAppear(_ animated: Bool) {
myTableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your outlets should be in cell class instead of viewcontroller because labels are inside cell
And in crllfor row at delegate you have to get your outlets like that
`let cell = tableView.dequeueReusableCell(withReuseIdentifier: cellIdentifier", for: indexPath) as! TableViewCellClass
cell.lbloutlet.text = "any text"
return cell
`
Create CustomTableCell subclassing UITableViewCell.
Have Labels in cell and connect to phoneNumberLabelOutlet & titleLabelOutlet in CustomTableCell class.
use CustomTableCell in place UITableViewCell for cellForRowAtIndex function.
now you can set values for labels as
cell.phoneNumberLabelOutlet.text = phoneNumberList[indexPath.row]
cell.titleLabelOutlet.text = titleFieldList[indexPath.row]
So I added a table view to a normal view controller and inside that table view I made a prototype cell. Ive done some work to make the cell appear but it won't. How do I fix this? Here is my code:
import UIKit
class NewsScreenViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var trendingButton: UITabBarItem!
#IBOutlet weak var newestButton: UITabBarItem!
#IBOutlet weak var topJournalists: UITabBarItem!
#IBOutlet weak var tabBar: UITabBar!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell")! as UITableViewCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
You need to return cell after you get the cell and give it something to display. Try something more like this
let fillTableViewArray = [String]()
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReuseableCellWithIdentifier("cell")
//now that you have that cell you have to put something into it. For example an Array of strings, can be used to fill the table view
cell!.textLabel?.text = fillTableViewArray[indexPath.row]
return cell!
}
If you want to do this in the storyboard, you can instead add a label to the prototype cell in the storyboard, set an integer value for the label's tag, and then find the label by adding these two lines after you do let cell = ...
let label = cell.viewWithTag(100) as UILabel!
label.text = fillTableViewArray[indexPath.row]
I hope this helps fix your issue