denzel banegas
denzel banegas

Reputation: 37

How to add multiple items to a UITableViewCell?

Can anyone help me get the email field to display in the tableView cell? The amount field is showing up, but I can't get the email to show along with it.

struct Posts {
    var amount:String
    var email:String
}

class PaymentRequestVC: UIViewController, UITableViewDelegate {
    
    let tableView = UITableView()
   
    var posts = [Posts]()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        self.tableView.dataSource = self
        self.tableView.delegate = self
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
        tableView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 900)
        setupViews()
        setupTableView()
        loadPosts()
        self.tableView.reloadData()
        
    
    }

    func loadPosts() {
        let dbUsers = Firestore.firestore().collection("Payouts")
        dbUsers.addSnapshotListener { (querySnapshot, error) in
            if let error = error {
                print("\(error.localizedDescription)")
            } else {
                for document in (querySnapshot?.documents)! {
                    if let Amount = document.data()["amount"] as? String {
                        let Email = document.data()["email"] as? String
                        print(Amount)
                        var post = Posts(amount: "", email: "")
                        post.amount = Amount
                        post.email = Email ?? ""

                        self.posts.append(post)
                    }
                }
                
                    self.tableView.reloadData()
                
                print(self.posts)
            }
        }
      }
    
    private func setupViews() {
    let stackView: UIStackView = {
        let sv = UIStackView()
        sv.translatesAutoresizingMaskIntoConstraints = false
        sv.spacing = 28
        sv.axis = .vertical
        sv.distribution = .fill
        sv.alignment = .fill
        return sv
        }()
        view.addSubview(stackView)
        view.addSubview(tableView)

    }
    
    func setupTableView() {
           
           NSLayoutConstraint.activate([
                  tableView.topAnchor.constraint(equalTo: self.view.topAnchor),
                  tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
                  tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
                  tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor)
              ])
           }
}

extension PaymentRequestVC: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
}

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row < posts.count {
                let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
                let post = posts[indexPath.row]
                cell.textLabel?.text = post.amount
                cell.textLabel?.textColor = UIColor.black
                return cell
            } else {
                let cell2 = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
                let post = posts[indexPath.row]
                cell2.detailTextLabel?.text = post.email
                cell2.detailTextLabel?.textColor = UIColor.black
                return cell2
            }
 }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 80
    }
}

Upvotes: 0

Views: 785

Answers (2)

Sebastian Salazar
Sebastian Salazar

Reputation: 161

Swift 5

You need to init the cell with UITableViewCell.CellStyle.subtitle for the detailTextLabel attribute to work.

In your extension, change the cell init:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row < posts.count {
            let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")
            let post = posts[indexPath.row]
            cell.textLabel?.text = post.amount
            cell.textLabel?.textColor = UIColor.black
            cell.detailTextLabel?.text = post.email
            cell.detailTextLabel?.textColor = UIColor.black
            return cell
        } else {
            let cell2 = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell2")
            let post = posts[indexPath.row]
            cell2.detailTextLabel?.text = post.email
            cell2.detailTextLabel?.textColor = UIColor.black
            return cell2
        }

Note that if you want the amount and the mail to both show up, using else will only display either the amount or the email, like in the code below

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row < posts.count {
            let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")
            let post = posts[indexPath.row]
            cell.textLabel?.text = post.amount
            cell.textLabel?.textColor = UIColor.black
            return cell
        } else {
            let cell2 = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell2")
            let post = posts[indexPath.row]
            cell2.detailTextLabel?.text = post.email
            cell2.detailTextLabel?.textColor = UIColor.black
            return cell2
        }

So a better approach would be to return both, and else display nothing

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row < posts.count {
            let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")
            let post = posts[indexPath.row]
            cell.textLabel?.text = post.amount
            cell.textLabel?.textColor = UIColor.black
            cell.detailTextLabel?.text = post.email
            cell.detailTextLabel?.textColor = UIColor.black
            return cell
        } else {
            let cell2 = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell2")
            //Empty cell returned if the condition above is not fulfilled
            return cell2
        }

Hope this helps.

Upvotes: 1

Gabriel Pires
Gabriel Pires

Reputation: 966

I think your logic in cellForRowAt is incorrect.

You have an array of Posts. And you want to display amount and email in the same cell right? One label being the title and the other being the detailed text.

Both labels are in the same UITableViewCell, so you only need to set it up once per post.

In addition, if indexPath.row is greater than the post count, then posts[indexPath.row] would actually crash your code. So that else statement should actually just log an error or simply do nothing.

Try something like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row < posts.count {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
            let post = posts[indexPath.row]
            cell.textLabel?.text = post.amount
            cell.textLabel?.textColor = UIColor.black
            cell.textLabel?.detailTextLabel?.text = post.email
            cell.textLabel?.detailTextLabel?.textColor = UIColor.black
            return cell
    } else {
            // No cells
    }
}

Upvotes: 0

Related Questions