Programmatic UITableView is showing one cell only - uitableview

A Swift newbie here. I'm trying to learn how to create different UI elements programmatically. I've hit the following wall..
I have 2 .swift files, on one hand we have...
import UIKit
struct MyTableView {
let myCustomTable: UITableView = {
let aTable = UITableView()
aTable.register(MyCustomCell.self, forCellReuseIdentifier: "myCell")
return aTable
}()
}
// custom cell class, then add subviews (UI controls) to it
class MyCustomCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(aLabel)
aLabel.frame = CGRect(x:0,
y:0,
width:self.frame.width,
height:self.frame.height)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// stuff to add to the cell
let aLabel: UILabel = {
let lbl = UILabel()
lbl.text = "My Custom Cell"
lbl.backgroundColor = UIColor.yellow // just to highlight it on the screen
return lbl
}()
On the other hand, we have the following view controller...
import UIKit
class ViewControllerA: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let instanceOfViewControllerTable = MyTableView()
override func loadView() {
super.loadView()
view.frame = UIScreen.main.bounds
instanceOfViewControllerTable.myCustomTable.delegate = self
instanceOfViewControllerTable.myCustomTable.dataSource = self
instanceOfViewControllerTable.myCustomTable.frame = CGRect(x:0,
y:0,
width:self.view.frame.width,
height:self.view.frame.height)
self.view.addSubview(instanceOfViewControllerTable.myCustomTable)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
}
}
It builds and runs successfully, however, I'm getting the following result:
Now, my thinking is if I'm doing something wrong, the cell shouldn't appear at all. What I don't understand, why is it showing only on one cell in the array?
Your help is highly appreciated.

You are declaring aLabel as a global variable. That way, only one instance exists from it. Move it inside your cell's class declaration.
class MyCustomCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(aLabel)
aLabel.frame = CGRect(x:0,
y:0,
width:self.frame.width,
height:self.frame.height)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let aLabel: UILabel = {
let lbl = UILabel()
lbl.text = "My Custom Cell"
lbl.backgroundColor = UIColor.yellow // just to highlight it on the screen
return lbl
}()
}

Related

Why doesn't my table view cell class instance run its initializer in my Swift code?

I have a custom subclass of UITableViewCell shown below
class GroupSelectionTableViewCell: UITableViewCell {
// MARK: - Properties
var groupSelectionLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.backgroundColor = .clear
label.font = UIFont.systemFont(ofSize: 18)
return label
}()
var groupSelectionImageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .clear
iv.setHeight(height: 25)
iv.setWidth(width: 25)
iv.contentMode = .scaleAspectFill
return iv
}()
// MARK: - LifeCycle
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
configureUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Helper Functions
private func configureUI() {
self.addSubview(groupSelectionLabel)
groupSelectionLabel.centerY(inView: self)
groupSelectionLabel.anchor(left: self.leftAnchor, paddingLeft: 12)
self.addSubview(groupSelectionImageView)
groupSelectionImageView.centerY(inView: self)
groupSelectionImageView.anchor(right: self.rightAnchor, paddingRight: 12)
self.backgroundColor = .black
self.selectionStyle = .none
}
}
and a custom subclass of UITableView shown below...
class GroupSelectionView: UITableView {
// MARK: - Properties
private let cellID = "GroupSelectionTableViewCell"
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
backgroundColor = .red
setHeight(height: 450)
setWidth(width: 300)
register(GroupSelectionTableViewCell.self, forCellReuseIdentifier: cellID)
rowHeight = 60
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension GroupSelectionView: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
return
}
}
extension GroupSelectionView: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
6
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! GroupSelectionTableViewCell
cell.groupSelectionLabel.text = "None"
cell.groupSelectionImageView.image = UIImage(named: "Tick")
return cell
}
}
But when I add my table view instance to a UIView() as a subview the table view cell class isn't running its initializer. Am I using the register method correctly? I have tried instantiating the table view subclass and putting a print statement in the initializer of the table view cell subclass but it doesn't get printed. Am I forgetting to set some property on the table view subclass? Do I need to use the Nib version of register instead? Any help would be greatly appreciated.
Forgot to set the dataSource and the delegate!

Wondering how I subclass UITableViewCell in swift 3.0 programmatically?

As the title implies I am trying to customize/subclass the UITableViewCell class in swift 3.0 programmatically and have the custom cells appears in a table.
I have the following subclass of UITableViewCell declared:
import Foundation
import UIKit
class TableViewCellCustom: UITableViewCell {
var myLabel: UILabel!
var myButton: UIButton!
let screenSize = UIScreen.main.bounds
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.backgroundColor = UIColor.blue
myLabel = UILabel()
myLabel.frame = CGRect(x: 180, y: 20.0, width: 50.0, height: 20.0)
myLabel.textColor = UIColor.black
myLabel.textAlignment = .center
contentView.addSubview(myLabel)
}
}
This should allow me to do the simple case of having a custom cell with a label in a specific location in the cell, of my designation. I am a bit confused though as to how I should integrate this into my ViewController where I am delegating the UITableView.
Currently my ViewController looks like so:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView: UITableView = UITableView()
var items: [String] = ["Party at Dougs", "Pillage at the Village", "Meow party at sams"]
let screenSize: CGRect = UIScreen.main.bounds
var appTitle: UIView! = nil
var appTitleText: UILabel! = nil
override func viewDidLoad() {
super.viewDidLoad()
let screenWidth = screenSize.width
let screenHeight = screenSize.height
tableView.frame = CGRect(origin: CGPoint(x: 0,y :screenHeight*0.12), size: CGSize(width: screenWidth, height: screenHeight*0.88))
tableView.delegate = self
tableView.dataSource = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "td")
cell.textLabel?.text = items[indexPath.row]
self.tableView.rowHeight = screenSize.height * 0.15
return cell
}
}
I think the core of my problem is being unsure how to connect my subclass of UITableViewCell to my TableView. How can I do this? thanks.
For custom cell created programmatically, without using xib, which is your case currently, you can use the below code -
instead of this
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
use this line
tableView.register(TableViewCellCustom.self, forCellReuseIdentifier: "cell")
Also instead of line
let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "td")
use this line
let cell = TableViewCellCustom(style: UITableViewCellStyle.default, reuseIdentifier: "td")
For when using xib to create custom cell . Use the below code in your UITableViewDataSource cellForAtIndexPath if you have xib for custom cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("td") as? TableViewCellCustom
if cell == nil {
tableView.registerNib(UINib(nibName: "TableViewCellCustom", bundle: nil), forCellReuseIdentifier: "td")
cell = tableView.dequeueReusableCellWithIdentifier("td") as? TableViewCellCustom
}
cell.textLabel?.text = items[indexPath.row]
self.tableView.rowHeight = screenSize.height * 0.15
return cell
}

Empty Cells in TableView with Custom TableViewCell - Swift

I am currently learning Swift programatically. I am wanting to add a tableView to a viewController (for the purpose of being able to manipulate the constraints later) and customize the cells with a TableViewCell.
I can do this with my eyes closed when using the storyboard, but when I try to do it with just straight code I have empty cells.
My storyboard is comprised of one (1) empty viewController that has the custom class of ViewController
I have looked at others with similar issues but non of the solutions have worked. Would love to know what I am overlooking (probably something simple). Thanks in advance for the help!
ViewController.swift:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var tableView: UITableView = UITableView()
var items: [String] = ["Viper", "X", "Games"]
override func viewDidLoad() {
tableView.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height)
tableView.delegate = self
tableView.dataSource = self
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(tableView)
}
func tableView(tableView:UITableView, heightForRowAtIndexPath indexPath:NSIndexPath)->CGFloat
{
return 50
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.items.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
//cell.textLabel?.text = self.items[indexPath.row]
cell.companyName.text = "name"
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
TableViewCell:
import UIKit
class TableViewCell: UITableViewCell {
var companyName = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Hello #Michael First thing is you should only use awakeFromNib when you are using a .xib(Nib) and in your case you are using custom class without such xib so, you should use
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
companyName = UILabel(frame: CGRectMake(0, 0, 200, 20))
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
also you should initialise your label before using it.
this will solve your problem.
Read apple's documentation for subclassing UITableViewCell here.
If you want your custom cell to load from some custom xib you do sometimes like:
tableView.registerNib(UINib(nibName: "CustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: "CustomTableViewCell")
And you should have CustomTableViewCell.xib file where you have table view cell with reuse identifier CustomTableViewCell
Checkout how your cell's companyLabel is laid out. Does it exist or no?
In your code, I replaced companyLabel with default textLabel and it worked for me.
cell.textLabel!.text = self.items[indexPath.row]
I think awakeFromNib is not called because you do not register a nib but a class. Try this instead:
class TableViewCell: UITableViewCell {
let companyName = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Initialization code
companyName.frame = CGRectMake(0, 0, 200, 20)
companyName.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(companyName)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Custom TableViewCell without storyboard

I am using custom cocoa class extends from TableViewCell and it doesn't give any error message but the cells do not appear in the tableview. The scroll gets longer but the table cells are not viewable.
I typed this in my ViewController :
tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)->UITableViewCell
{
var cell:CustomTableViewCell? = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? CustomTableViewCell
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
cell!.labTime.text = filtered[indexPath.row].name!
return cell!
}
and my cell class looks like
var labTime = UILabel()
override func awakeFromNib() {
// Initialization code
super.awakeFromNib()
labTime = UILabel(frame: contentView.bounds)
labTime.font = UIFont(name:"HelveticaNeue-Bold", size: 16)
contentView.addSubview(labTime)
}
I don't use any storyBoard or xib file.
Can not find the solution,
thanks
Do this way.
All view intialization of properties should go in init method.
Add this in your custom cell class
var labTime: UILabel!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
//Do your cell set up
labTime = UILabel(frame: contentView.bounds)
labTime.font = UIFont(name:"HelveticaNeue-Bold", size: 16)
contentView.addSubview(labTime)
}
Add the below line in viewDidLoad method of your view controller.
tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
Set these two delegate - UITableViewDataSource and UITableViewDelegate

Assigning property of custom UITableViewCell

I am using the below custom UITableViewCell without nib file.
I have no problem in viewing it in my UITableViewController.
My problem is with assigning a text to "name" label cell.name.text = "a Name" .. noting is assigned
Can you help me?
import UIKit
class ACMenuCell: UITableViewCell {
#IBOutlet var name : UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
name = UILabel(frame: CGRectMake(20, 10, self.bounds.size.width , 25))
name.backgroundColor = .whiteColor()
self.contentView.addSubview(name)
self.contentView.backgroundColor = .blueColor()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func layoutSubviews() {
super.layoutSubviews()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
You might want to try this: Create a public function in a subclass of UITableViewCell, and inside this funxtion set the text to label.
(void)initializeCell
{
do whatever like setting the text for label which is a subview of tableViewCell
}
And from cellForRowAtIndexPAth, call this function on cell object:
// taking your code for demo
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let reuseIdentifierAC:NSString = "ACMenuCell"; var cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifierAC, forIndexPath:indexPath) as ACMenuCell cell = ACMenuCell(style: UITableViewCellStyle.Default, reuseIdentifier: reuseIdentifierAC) [cell initializeCell] return cell }
This approach has worked for me.

Resources