How to set a label in a cell of tableview by code? - ios

If I just want to set a label by code, I should write for example like this,
let label = UILabel()
label.frame = CGRect(x:10, y: 10, width:160, height:30)
label.text = "Test"
self.view.addSubview(label)
but if I want to set a label in a cell of tableView, how can I set it?
Thanks!

You should create you a custom class for you cell as such. This adds a label to a cell and uses anchoring system to set constraints on the label to fill the entire cell.
class CustomCell: UITableViewCell {
let label: UILabel = {
let n = UILabel()
n.textColor = UIColor.darkGray
n.textAlignment = .center
n.text = "Testing 123"
n.font = UIFont(name: "Montserrat", size: 30)
return n
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
label.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
For the ViewController that uses this custom cell, you have to add the below cell registration like such, unless you're using storyboards/interface builder.
class ControllerUsesCell: UITableViewController {
let defaultCellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
tableView?.register(CustomCell.self, forCellWithReuseIdentifier: defaultCellId)
}
}

UITableviewCell subclass has textlabel property which you can use
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = "My Text"
return cell
}
or alternatively you can use custom cell for more control
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
let label = UILabel()
label.frame = CGRect(x: 10, y: 10, width: 160, height: 30)
label.text = "Test"
cell.contentView.addSubview(label)
return cell
}

Related

Adding top and bottom constraints causes UILable to be squished

Programmatically I created a custom UITableViewCell and tried centering two UILabels vertically inside it. But the UILabel ended up being squished. Doing the same thing in Interface Builder with a prototype cell works well. What is wrong with my code?
The Custom view cell class
import UIKit
class TopViewCell: UITableViewCell {
let df: DateFormatter = {
let df = DateFormatter()
df.dateFormat = NSLocalizedString("DATE_WEEKDAY", comment: "show date and weekday")
return df
}()
var dateLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var costLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let margin = contentView.layoutMarginsGuide
contentView.addSubview(dateLabel)
dateLabel.leadingAnchor.constraint(equalTo: margin.leadingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: margin.topAnchor).isActive = true
dateLabel.bottomAnchor.constraint(equalTo: margin.bottomAnchor).isActive = true
contentView.addSubview(costLabel)
costLabel.trailingAnchor.constraint(equalTo: margin.trailingAnchor).isActive = true
costLabel.topAnchor.constraint(equalTo: dateLabel.topAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
dateLabel.text = df.string(from: Date())
costLabel.text = "total: five thousand"
}
}
The Custom UITableViewController class
import UIKit
class ItemViewController: UITableViewController {
var itemStore: ItemStore!
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TopViewCell.self, forCellReuseIdentifier: "top_cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemStore.allItems.count + 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: UITableViewCell!
if indexPath.row == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: "top_cell", for: indexPath)
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = itemStore.allItems[indexPath.row - 1].name
cell.textLabel?.font = cell.textLabel!.font.withSize(30)
cell.detailTextLabel?.text = "$\(itemStore.allItems[indexPath.row - 1].valueInDolloar)"
}
return cell
}
}
Your TopViewCell is not auto-sizing correctly because you're setting the text in layoutSubviews(). Move those two lines to init and it will size properly:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let margin = contentView.layoutMarginsGuide
contentView.addSubview(dateLabel)
dateLabel.leadingAnchor.constraint(equalTo: margin.leadingAnchor).isActive = true
dateLabel.topAnchor.constraint(equalTo: margin.topAnchor).isActive = true
dateLabel.bottomAnchor.constraint(equalTo: margin.bottomAnchor).isActive = true
contentView.addSubview(costLabel)
costLabel.trailingAnchor.constraint(equalTo: margin.trailingAnchor).isActive = true
costLabel.topAnchor.constraint(equalTo: dateLabel.topAnchor).isActive = true
// set the text here
dateLabel.text = df.string(from: Date())
costLabel.text = "total: five thousand"
}
As a side note, you should specify the class when you use TopViewCell:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "top_cell", for: indexPath) as! TopViewCell
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = itemStore.allItems[indexPath.row - 1].name
cell.textLabel?.font = cell.textLabel!.font.withSize(30)
cell.detailTextLabel?.text = "$\(itemStore.allItems[indexPath.row - 1].valueInDolloar)"
return cell
}
As another side note... you can create two prototype cells in your Storyboard.

How to add subview to stackview in table view cell?

I am in need to add the label as subview to UIStackView in table view cell.
I have created label as
let nameLabel=UILabel()
nameLabel.text=names[indexPath.row]
Where name is an array which is a type of String
My code is
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
{
let names=["Amutha","Priya","Amuthapriya","Priyasri","Kavisha"]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell
{
let cell=tableView.dequeueReusableCell(withIdentifier: "cell") as! ViewCell
for name in names
{
let nameLabel=UILabel()
nameLabel.text=name
cell.nameStackView!.addSubview(nameLabel)
}
return cell
}
}
Why I am getting a null pointer exception when I add a label to stackview?
Any help will be much appreciated.
Change
cell.nameStackView!.addSubview(nameLabel)
To
cell.nameStackView!.addArrangedSubview(nameLabel)
You can use below code to add UIStackView as per your need.
let titleLabel = UILabel()
let subtitleLabel = UILabel()
lazy var titleStackView: UIStackView = {
titleLabel.textAlignment = .center
titleLabel.text = "Good Morning"
titleLabel.textColor = UIColor.white
titleLabel.font = UIFont(name: "ProximaNova-Regular", size: 12.0)
subtitleLabel.textAlignment = .center
subtitleLabel.text = "--"
subtitleLabel.textColor = UIColor.white
subtitleLabel.heightAnchor.constraint(equalToConstant: 30.0).isActive = true
subtitleLabel.font = UIFont(name: "DublinSpurs", size: 20.0)
let stackView = UIStackView(arrangedSubviews: [subtitleLabel])
stackView.axis = .vertical/.horizontal
return stackView
}()
Also try replacing
for name in names
{
let nameLabel=UILabel()
nameLabel.text=name
cell.nameStackView!.addSubview(nameLabel)
}
with
let nameLabel=UILabel()
nameLabel.text = names[indexPath.row]
cell.nameStackView!.addSubview(nameLabel)
If you have nameStackView in storyboard or xib, make sure the IBOutlet is connected properly. If you have created the nameStackView programmatically make sure it is initialised.
And remove all existing labels from the stackview, else you'll have duplicate labels on each scroll
class ViewCell: UITableViewCell {
//Make sure IBOutlet is connected properly
#IBOutlet weak var nameStackView: UIStackView!
}
ViewController
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ViewCell
for name in names
{
cell.nameStackView.arrangedSubviews.forEach { cell.nameStackView.removeArrangedSubview($0) }
let nameLabel=UILabel()
nameLabel.text=name
cell.nameStackView.addSubview(nameLabel)
}
return cell
}
Try below code
let nameLabel = UILabel()
cell.nameStackView.addArrangedSubview(nameLabel)
Try initializing the stackview and label in your ViewCell class.
class ViewCell: UITableViewCell {
let nameLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14)
return label
}()
let nameStackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
return stackView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super .init(style: style, reuseIdentifier: reuseIdentifier)
self.configureStackView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureStackView()
{
addSubview(nameStackView)
nameStackView.translatesAutoresizingMaskIntoConstraints = false
nameStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true
nameStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
nameStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
nameStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
nameStackView.addArrangedSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.topAnchor.constraint(equalTo: nameStackView.topAnchor,
constant:10).isActive = true
nameLabel.leadingAnchor.constraint(equalTo: nameStackView.leadingAnchor,
constant:10).isActive = true
nameLabel.trailingAnchor.constraint(equalTo: nameStackView.trailingAnchor,
constant:-10).isActive = true
nameLabel.bottomAnchor.constraint(equalTo: nameStackView.bottomAnchor,
constant:-10).isActive = true
}
}
This code is in case you didn't create your stackview in storyboard.
Now in your ViewController class, add the following code in your cellForRowAt method.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->
UITableViewCell
{
let cell=tableView.dequeueReusableCell(withIdentifier: "cell") as! ViewCell
cell.nameLabel.text = names[indexPath.row]
return cell
}
Hope, this solution works for you.

How to expand and collapse tableview cells with dynamic height programmatically?

Here is a video of my problem: https://imgur.com/a/qvGSLfD
My custom cell has 2 labels: one main label, and a subtitle label, both of which are constrained to the cell's contentView layoutMarginsGuide in all directions.
First of all, the whole expand collapse mechanism seems a bit clunky since I'm activating and deactivating constraints and then reloading the indexPaths.
I've tried this approach: When I select the cell, I deactivate the constraints that are responsible for setting only one label and activate the constraints for both, and when it collapses I do the opposite. I feel like this is not a good approach but I was not able to find anything that supported dynamic cell heights.
Basically, I could’ve done something like this:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex {
return 200 //Expanded
}
return tableView.rowHeight //Not expanded
}
but I can't just return the same number for cells that are sized differently.
Here is my tableView code in my viewController class:
var tableView: UITableView = {
let tv = UITableView(frame: .zero)
tv.register(CustomCell.self, forCellReuseIdentifier: CustomCell.reuseIdentifier())
tv.translatesAutoresizingMaskIntoConstraints = false
tv.rowHeight = UITableView.automaticDimension
tv.estimatedRowHeight = 60.0
tv.estimatedSectionHeaderHeight = 0
tv.estimatedSectionFooterHeight = 0
tv.showsVerticalScrollIndicator = false
tv.tableFooterView = UIView()
tv.alwaysBounceVertical = true
tv.decelerationRate = .fast
tv.bounces = false
tv.dataSource = self
tv.delegate = self
return tv
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.reuseIdentifier(), for: indexPath) as! CustomCell
cell.bounds = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 99999)
cell.contentView.bounds = cell.bounds
cell.layoutIfNeeded()
cell.wordLabel.preferredMaxLayoutWidth = cell.wordLabel.frame.width
cell.descriptionLabel.preferredMaxLayoutWidth = cell.descriptionLabel.frame.width
//customize this later
cell.backgroundColor = .white
cell.set(content: datasource[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
cell.toggle()
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Here are the relevant custom Cell functions:
var isExpanded: Bool!
private var singleLabelConstraints: [NSLayoutConstraint]!
private var doubleLabelConstraints: [NSLayoutConstraint]!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupLabels()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLabels()
}
func toggle() {
isExpanded = !isExpanded
if isExpanded == false {
print("collapsed")
self.descriptionLabel.isHidden = true
NSLayoutConstraint.activate(singleLabelConstraints)
NSLayoutConstraint.deactivate(doubleLabelConstraints)
} else if isExpanded == true {
print("expanded")
self.descriptionLabel.isHidden = false
NSLayoutConstraint.deactivate(singleLabelConstraints)
NSLayoutConstraint.activate(doubleLabelConstraints)
}
}
func setupLabels() {
isExpanded = false
descriptionLabel.isHidden = true
self.contentView.addSubview(wordLabel)
self.contentView.addSubview(descriptionLabel)
singleLabelConstraints = [
wordLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
wordLabel.topAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.topAnchor,
constant: labelInsets.top
),
wordLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
wordLabel.bottomAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
constant: labelInsets.bottom
)
]
doubleLabelConstraints = [
wordLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
wordLabel.topAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.topAnchor,
constant: labelInsets.top
),
wordLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
descriptionLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
descriptionLabel.topAnchor.constraint(
equalTo: self.wordLabel.bottomAnchor,
constant: labelInsets.top
),
descriptionLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
descriptionLabel.bottomAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
constant: labelInsets.bottom
)
]
NSLayoutConstraint.activate(singleLabelConstraints)
}
I expected the transition to be smoother and I want something that can easily toggle the cell while keeping the main label in place and just show then subtitle label.
You can use UIStackView for expand and collapse tableview. You can hide and show the description label when tableview cell is selected.
class ViewController: UIViewController {
var tableView: UITableView = {
let tv = UITableView(frame: .zero)
tv.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
tv.translatesAutoresizingMaskIntoConstraints = false
tv.rowHeight = UITableView.automaticDimension
tv.estimatedRowHeight = 100.0
tv.estimatedSectionHeaderHeight = 0
tv.estimatedSectionFooterHeight = 0
tv.showsVerticalScrollIndicator = false
tv.tableFooterView = UIView()
tv.alwaysBounceVertical = true
tv.decelerationRate = .fast
tv.bounces = false
return tv
}()
var selectedCell:IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell ?? CustomCell()
if let selectedCell = selectedCell, selectedCell == indexPath {
cell.descriptionLabel.isHidden = false
} else {
cell.descriptionLabel.isHidden = true
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell = indexPath
tableView.reloadData()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
class CustomCell: UITableViewCell {
let stackView = UIStackView()
let wordLabel = UILabel()
let descriptionLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupLabels()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLabels()
}
func setupLabels() {
selectionStyle = .none
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(stackView)
wordLabel.translatesAutoresizingMaskIntoConstraints = false
wordLabel.text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lor"
wordLabel.numberOfLines = 0
wordLabel.lineBreakMode = .byWordWrapping
stackView.addArrangedSubview(wordLabel)
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
descriptionLabel.numberOfLines = 0
descriptionLabel.lineBreakMode = .byWordWrapping
stackView.addArrangedSubview(descriptionLabel)
wordLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
descriptionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,constant: 10).isActive = true
stackView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor,constant: 10).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,constant: 10).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,constant: 10).isActive = true
}
}
Try this:
tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
hello there you can overcome the problem by going through this link below,
http://vasundharavision.com/blog/ios/expandable-tableview-without-third-party
i hope it works for you.

UITableViewCell behaves differently in iOS 11

I have done a UITableViewCell programmatically and it worked just fine with iOS 10. But after updating with iOS 11 and XCode 9, it behaves differently. The layout looks scrambled as below.
But if I tap on the cell then it rearranges and looks fine as below.
Here the code for UITableViewCell
import UIKit
import SnapKit
class AboutCell: UITableViewCell {
let roleLabel : UILabel = {
var tablelabel = UILabel()
tablelabel.font = UIFont (name: "Avenir Next Medium", size: 22)
tablelabel.textAlignment = .center
tablelabel.clipsToBounds = true
tablelabel.translatesAutoresizingMaskIntoConstraints = false
return tablelabel
}()
let nameLabel : UILabel = {
let tablelabel = UILabel()
tablelabel.font = UIFont (name: "Avenir Next Medium", size: 16)
tablelabel.textAlignment = .center
tablelabel.clipsToBounds = true
tablelabel.translatesAutoresizingMaskIntoConstraints = false
return tablelabel
}()
let webUrlLabel : UILabel = {
let tablelabel = UILabel()
tablelabel.font = UIFont (name: "Avenir Next Medium", size: 16)
tablelabel.textAlignment = .center
tablelabel.clipsToBounds = true
tablelabel.translatesAutoresizingMaskIntoConstraints = false
return tablelabel
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
override func layoutSubviews() {
super.layoutSubviews()
roleLabel.frame = CGRect(x: 0, y: 10, width: self.contentView.bounds.size.width-20, height: 25)
nameLabel.frame = CGRect(x: 0, y: roleLabel.frame.origin.y+25, width: self.bounds.size.width-20, height: 25)
webUrlLabel.frame = CGRect(x: 0, y: nameLabel.frame.origin.y+25, width: self.bounds.size.width-20, height: 25)
}
func setupViews(){
contentView.addSubview(roleLabel)
contentView.addSubview(nameLabel)
contentView.addSubview(webUrlLabel)
}
func setValuesForCell(contributor : Contributors){
roleLabel.text = contributor.contributorRole
nameLabel.text = contributor.contributorName
webUrlLabel.text = contributor.contributorWeb
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
and the extension I wrote for TableView delegate and datasource
extension AboutController : UITableViewDelegate, UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contributorList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : AboutCell = tableView.dequeueReusableCell(withIdentifier: self.cellid, for: indexPath) as! AboutCell
cell.selectionStyle = .default
let contributor : Contributors = contributorList[indexPath.row]
cell.setValuesForCell(contributor: contributor)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
tableView.deselectRow(at: indexPath, animated: true)
}
}
and the ViewDidLoad method
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 100.0
tableView.rowHeight = 100
tableView.register(AboutCell.self, forCellReuseIdentifier: self.cellid)
view.addSubview(tableView)
tableView.snp.makeConstraints { (make) in
make.top.right.bottom.left.equalToSuperview()
}
let mayu = Contributors(contibutorRole: "Developer", contributorName: "J Mayooresan", contributorWeb: "http://jaymayu.com")
let janie = Contributors(contibutorRole: "Voice Artist", contributorName: "M Jananie", contributorWeb: "http://jaymayu.com")
let arjun = Contributors(contibutorRole: "Aathichudi Content", contributorName: "Arjunkumar", contributorWeb: "http://laymansite.com")
let artist = Contributors(contibutorRole: "Auvaiyar Art", contributorName: "Alvin", contributorWeb: "https://www.fiverr.com/alvincadiz18")
contributorList = [mayu, arjun, janie, artist]
tableView.delegate = self
tableView.dataSource = self
self.tableView.reloadData()
}
Since you're laying out your tableView using autolayout, you also need to ensure translatesAutoresizingMaskIntoConstraints is set to false.
SnapKit should be setting the tableView's translatesAutoresizingMaskIntoConstraints to false for you already.
Since you're laying out the cells manually (using frames in layoutSubviews). Setting the cells subview's translatesAutoresizingMaskIntoConstraints to false is likely not needed.
See Apple Docs here for translatesAutoresizingMaskIntoConstraints

(Swift) Tableview cell: textLabel showing up, but detailTextLabel isn't

I set up a table view in storyboard and gave it a custom cell class:
Storyboard:
Cell class:
class CommentCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
textLabel?.frame = CGRect(x: 100, y: textLabel!.frame.origin.y - 2, width: textLabel!.frame.width, height: textLabel!.frame.height)
detailTextLabel?.frame = CGRect(x: 100, y: detailTextLabel!.frame.origin.y + 2, width: detailTextLabel!.frame.width, height: detailTextLabel!.frame.height)
}
let logoView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.layer.borderWidth = 1
imageView.layer.cornerRadius = 24
imageView.layer.masksToBounds = true
return imageView
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
addSubview(logoView)
logoView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8).isActive = true
logoView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
logoView.widthAnchor.constraint(equalToConstant: 48).isActive = true
logoView.heightAnchor.constraint(equalToConstant: 48).isActive = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
And then in my view controller I gave it some dummy text to test it out, and the textLabel text shows up fine, but the detailTextLabel text and the imageView do not.
#IBOutlet weak var tableView: UITableView!
let commentors = ["Person One", "Person Two", "Person Three"]
let comments = ["Comment One", "Comment Two", "Comment Three"]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CommentCell
cell.textLabel?.text = commentors[indexPath.row]
cell.detailTextLabel?.text = comments[indexPath.row]
DispatchQueue.main.async {
cell.logoView.image = UIImage(named: "testImage")
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return commentors.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72
}
This is what I see when I run the app:
Anyone know why the textLabel is showing up but not the detailTextLabel or the image?
A table view cell with style custom has no implicit detailTextLabel and no imageView.
You have to implement the elements in the storyboard and connect them to appropriate IBOutlets.
#vadian's answer is correct, however, you do not have to add the other label manually.
I was facing the same issue and realised while looking at your question that the type of the cell in the Interface Builder is Custom and not subtitle. You initialise it correctly, but it seems like the style set in the IB has priority.
subtitle style makes sure that the detailTextLabel shows up and shows it already in the storyboard.
Hope this helps others.

Resources