Vyachaslav Gerchicov
Vyachaslav Gerchicov

Reputation: 2457

UITableViewCell with UIStackView with varying items?

I have a typical UITableView with custom cells. All cells are of the same type - one UIStackView which contains the views of the same type but varies their count.

Tried to use one cell for all - it is slow to delete-add inner views.

Tried to create different cells for different count of subviews:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let row = rows[indexPath.row]
        let CellIdentifier = "CellIdentifier\(row.subrows.count)"
        var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as? CustomCell
        if cell == nil {
            tableView.register(UINib(nibName: "WTRemindersTableViewCell", bundle: nil), forCellReuseIdentifier: CellIdentifier)
            cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as? CustomCell
            for _ in row.subrows {
                let v = Bundle.main.loadNibNamed("CustomInnerView", owner: self, options: nil)?.first as! WTRemindersCellLineView
                cell!.stackView.addArrangedSubview(v)
            }
        }
        return cell!
    }

but it seems it registers just a cell without of subviews and it has no sense to use different cell identifiers (because each time you need to add stackview subviews manually).

How to solve this issue?

Edited

Added code for cell

class CustomCell: UITableViewCell {
    @IBOutlet var boxView: UIView!
    @IBOutlet var imgView: UIImageView!
    @IBOutlet var lblTitle: UILabel!
    @IBOutlet var lblSubtitle: UILabel!
    @IBOutlet var dashedView: WTDashedView!
    @IBOutlet var stackView: UIStackView!
    
    weak var delegate: CustomCellDelegate?
    var index: Int!
    
    lazy var onceDraw: () = {
        boxView.layer.applySketchShadow()
    }()
    
    override func awakeFromNib() {
        super.awakeFromNib()
        boxView.layer.cornerRadius = 19
        imgView.layer.cornerRadius = 12
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        _=onceDraw
    }
    
    @IBAction func btnDotsClicked(_ sender: Any) {
        delegate?.btnDotsClicked(at: index)
    }
}

Upvotes: 0

Views: 936

Answers (1)

Rob C
Rob C

Reputation: 5073

First, you should register your cell in viewDidLoad. Note I'm not sure what your nib is named, so make sure to adjust it for your needs.

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.register(
        UINib(nibName: "CustomCell", bundle: nil),
        forCellReuseIdentifier: "CustomCell"
    )
}

It's hard to tell what you were doing in your cellForRowAt method but this will do the trick. Cells are reused so make sure that you remove any remaining arranged subviews. You shouldn't have any performance issues if you do it this way:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell

    let row = rows[indexPath.row]

    cell.stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
    for _ in row.subrows {
        cell.stackView.addArrangedSubview(cellView())
    }

    return cell
}

This is just a little helper method to instantiate your view:

func cellView() -> WTRemindersCellLineView {
    return Bundle.main.loadNibNamed(
        "WTRemindersCellLineView", owner: nil, options: nil
        )?.first as! WTRemindersCellLineView
}

Upvotes: 0

Related Questions