I intended to display data from my Firestore Database into my app using the TableViewCell. It supposed to show the bookTitle, bookAuthor and bookSummary but the bookAuthor does not show up. Below is my code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text = books[indexPath.row].bookTitle
cell.textLabel?.font = .systemFont(ofSize: 20, weight: .medium)
cell.detailTextLabel?.text = books[indexPath.row].bookAuthor
cell.detailTextLabel?.text = books[indexPath.row].bookSummary
return cell
}
func setupTableView() {
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.allowsSelection = true
tableView.isUserInteractionEnabled = true
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return books.count
}
You're setting the same label to bookAuthor and bookSummary here:
cell.detailTextLabel?.text = books[indexPath.row].bookAuthor
cell.detailTextLabel?.text = books[indexPath.row].bookSummary
So, it gets set to bookAuthor, and then immediately overwritten by bookSummary.
You could create/use another label for one of the fields, or concatenate the strings for this single label:
cell.detailTextLabel?.text = "\(books[indexPath.row].bookAuthor ?? "") - \(books[indexPath.row].bookSummary ?? "")"
As You had used textLabel and detailTextLabel: It's used for giving label and a subtitle. You can't use detailTextLabel twice. So its overriding your bookAuthor by bookSummary.
Please try to write like this:-
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
cell.accessoryType = .disclosureIndicator
cell.textLabel?.text = books[indexPath.row].bookTitle
cell.textLabel?.font = .systemFont(ofSize: 20, weight: .medium)
cell.detailTextLabel?.text = books[indexPath.row].bookAuthor + "\n" + books[indexPath.row].bookSummary
return cell
}
Related
I am trying to add some icons to right side of a tableView cell. You can imagine it like "mute" icon of WhatsApp but it does not show icons in cells.
Here is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
var content = cell.defaultContentConfiguration()
let countryNames = Array(countryInfos.keys)
content.text = countryNames[indexPath.row]
cell.contentConfiguration = content
let myImage = UIImage(named:"star")
cell.imageView?.image = myImage
return cell
}
I tried like this also:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
var content = cell.defaultContentConfiguration()
let countryNames = Array(countryInfos.keys)
content.text = countryNames[indexPath.row]
cell.contentConfiguration = content
let myImage = UIImage(named:"star")
cell.imageView?.image = myImage
return cell
}
How can I make it visible and add it to the right side of a cell?
Current UI:
Expectation:
Note: star image is in the "Assets" folder as star.png
I think you can use custom cell and use stackView for text and image:
class CustomCell: UITableViewCell {
var customLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var customImage: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
var stackView: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.axis = .horizontal
stack.distribution = .fill
stack.alignment = .fill
return stack
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
stackView.addArrangedSubview(customLabel)
stackView.addArrangedSubview(customImage)
addSubview(stackView)
setupConstraints()
}
func setupConstraints(){
stackView.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
stackView.rightAnchor.constraint(equalTo: rightAnchor, constant: -20).isActive = true
stackView.topAnchor.constraint(equalTo: topAnchor, constant: 5).isActive = true
stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -5).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
then you have to register the cell in viewDidLoad
tableView.register(CustomCell.self, forCellReuseIdentifier: "cell")
and use it like so:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? CustomCell {
cell.customLabel.text = countries[indexPath.row]
cell.customImage.image = UIImage(systemName: "star")
return cell
}
return UITableViewCell()
}
Create a CustomCell with XIB.
Use Label and Image, and give constraints
Use the CustomCell class in your Tableview.
Register your cell:
YourTableViewName.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
Then use your CustomCell:
To access your CustomCell image, do:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = YourTableViewName.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as? CustomCell else {
return UITableViewCell()}
let myImage = UIImage(named:"star")
cell.imageView?.image = myImage
return cell
}
I am relatively new to UIKit. Currently, I am trying to create a UISwitch that will show up on a specific UITableView cell. However, I can't seem to figure out how to do this. Instead, I am getting a UISwitch on every single cell in the UITableView.
My code is below:
import UIKit
class SettingsVC: UIViewController {
var tableView = UITableView(frame: .zero, style: .insetGrouped)
let cells = ["Change Accent Color", "Change Currency Symbol", "Vibrations"]
let cellReuseIdentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
createTableView()
setTableViewDelegates()
}
func createTableView() {
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
}
extension SettingsVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
return cell
}
}
This is how my UITableView looks currently in the simulator.
This is how I would like the UITableView to look.
How would I be able to achieve the look I'm going for? Any help would be greatly appreciated.
The method tableView(_:cellForRowAt:) is used to create all cells for a table, so the code inside this method is called for each cell. You need to figure out a condition that distinguishes the cell with a UISwitch and run the corresponding piece conditionally. Conceptually, something like this:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if isSwitchNeeded { // Here.
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
}
return cell
}
There are some architectural options that might allow you do that. One of them is to rely on the index path. For instance, this should work in your raw example:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if indexPath.row == 2 {
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
}
return cell
}
And a million other ways.
First of all most likely you want to save the value of the switch, so create a property on the top level of the view controller
var enableVibrations = false
Second of all cells are reused. Even if there are only three cells it's good practice to set all UI elements to a defined state, that means to set the accessory view to nil if there is no switch.
And there is a dequeueReusableCell API which returns a non-optional cell.
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let title = cells[indexPath.row]
cell.textLabel?.text = title
if title == "Vibrations" {
let switchView = UISwitch(frame: .zero)
switchView.setOn(enableVibrations, animated: true)
switchView.addTarget(self, action: #selector(toggleVibrations), for: .valueChanged)
cell.accessoryView = switchView
} else {
cell.accessoryView = nil
}
return cell
}
And add the action method
#objc func toggleVibrations(_ sender : UISwitch) {
self.enableVibrations = sender.isOn
}
I am implementing UITableViewController Programmatically (No Storyboards!).
I tried many possible ways to implement automatic resizing of TableViewCell's detailTextLabel but none is working. I don't know what I am missing or whether it's a bug! Here's what I tried:
//Class - tableViewContoller
override func viewDidLoad() {
super.viewDidLoad()
setUpTableView()
}
func setUpTableView() {
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
tableView.contentInset = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension //Tried 44 -> Not working either
tableView.reloadData()
}
//cellForRowAt IndexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCell.CellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = caseDetails?.details
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = caseDetails?.bio
default:break
}
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
I have 2-3 cells where detailTextLabel may have multiple lines.
Please let me know what's that I'm missing here. What I figured after reading on the Internet is to add custom constraints, but I don't think that'll work either.
You have to add constraints for that cell?.detailTextLabel
cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
cell?.detailTextLabel?.layer.backgroundColor = UIColor.yellow.cgColor
// ALLOW MANUAL CONSTRAINTS
cell?.detailTextLabel?.translatesAutoresizingMaskIntoConstraints = false
// TOP +15, BOTTOM -15, RIGHT -15
cell?.detailTextLabel?.topAnchor.constraint(equalTo: (cell?.contentView.topAnchor)!, constant: 15).isActive = true
cell?.detailTextLabel?.bottomAnchor.constraint(equalTo: (cell?.contentView.bottomAnchor)!, constant: -15).isActive = true
cell?.detailTextLabel?.rightAnchor.constraint(equalTo: (cell?.contentView.rightAnchor)!, constant: -10).isActive = true
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = "hi\nhello\nwelcome\nhow are you"
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = "caseDetails?.bio\n\n\n123456"
default:break
}
return cell!
}
Output
Should work if you set your estimated row height to an actual value. You can't have both set to .automaticDimension.
I have a UITableView as a cell of another UITableView (nested UITableViews).
There is a top padding that I can't reason for, the top padding only appears when I make the CustomTableCell has a UITableView.
class CustomTableCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
private let cellId = "cellId"
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .grouped)
tv.translatesAutoresizingMaskIntoConstraints = false
tv.backgroundColor = .green
tv.delegate = self
tv.dataSource = self
tv.alwaysBounceVertical = false
tv.isScrollEnabled = false
tv.separatorColor = .red;
tv.separatorStyle = .none;
tv.register(InnerTableCell.self, forCellReuseIdentifier: self.cellId)
return tv
}()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! InnerTableCell
return cell
}
func setupAutoLayout() {
tableView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .white
contentView.addSubview(tableView)
setupAutoLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the link to entire code: https://ideone.com/QAxkPR
Here is how it looks in reveal
Change style to .plain instead of .grouped
let tv = UITableView(frame: .zero, style: .plain)
I have a table view which is set up correctly, but nothing is showing up. The arrays are populated and all the delegates are set up correctly. How do I fix this?
override func viewDidLoad() {
super.viewDidLoad()
self.friendstable.rowHeight = 150.0
friendstable.allowsSelection = false
self.friendstable.dataSource = self
self.friendstable.delegate = self
self.friendstable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "friendcell")
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titleofsong.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//var cell = friendstable.dequeueReusableCellWithIdentifier("friendcell", forIndexPath: indexPath)
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "friendcell")
cell.textLabel?.text = titleofsong[indexPath.row]
cell.detailTextLabel?.text = artist[indexPath.row]
cell.textLabel?.font = UIFont(name: "Lombok", size: 22)
cell.textLabel?.textColor = UIColorFromRGB("4A90E2")
cell.detailTextLabel?.font = UIFont(name: "Lombok", size: 16)
cell.detailTextLabel?.textColor = UIColor.blackColor()
cell.textLabel?.numberOfLines = 0;
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.backgroundColor = UIColor.clearColor()
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.friendstable.rowHeight = 150.0
friendstable.allowsSelection = false
self.friendstable.dataSource = self
self.friendstable.delegate = self
self.friendstable.registerNib(UINib(nibName:"YOUR_NIB_FILE_NAME", bundle:nil), forCellReuseIdentifier:"friendcell")
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : UITableViewCell= tableView.dequeueReusableCellWithIdentifier("friendcell", forIndexPath: indexPath)
cell.textLabel?.text = titleofsong[indexPath.row]
cell.detailTextLabel?.text = artist[indexPath.row]
cell.textLabel?.font = UIFont(name: "Lombok", size: 22)
cell.textLabel?.textColor = UIColorFromRGB("4A90E2")
cell.detailTextLabel?.font = UIFont(name: "Lombok", size: 16)
cell.detailTextLabel?.textColor = UIColor.blackColor()
cell.textLabel?.numberOfLines = 0;
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
cell.backgroundColor = UIColor.clearColor()
return cell
}