Programmatically creating an expanding UItableViewCell

前端 未结 3 1413
南方客
南方客 2020-11-27 08:29

I have a tableviewcell that I want to expand and collapse on tap. All the examples I have found are Storyboard base and I am trying to do this programmatically. What I thoug

3条回答
  •  情书的邮戳
    2020-11-27 08:41

    Use vertical UIStackView with the bottom view isHidden set to true, then on tap (or whatever is the trigger of the expand) just change the isHidden = false. I guess that would be the easiest, considering how UIStackView deals with isHidden. Another approach is to setup autolayout constraints, and change height anchor of the bottom view by setting NSLayoutConstraint's constant to 0.

    Anyway, whichever of the appraoch will you choose, you will have to tell the tableView to refresh its display (from the viewcontroller):

    func refreshTableAfterCellExpansion() {
        self.tableView.beginUpdates()
        self.tableView.setNeedsDisplay()
        self.tableView.endUpdates()
    }
    

    E.g., check following SO question and its answer.

    An example using playgrounds (the one with the UIStackView, the other one uses the same principle):

    import UIKit
    import PlaygroundSupport
    
    class ExpandableCellViewController: UITableViewController, ExpandableCellDelegate {
    
        override func loadView() {
            super.loadView()
    
            tableView.rowHeight = UITableViewAutomaticDimension
            tableView.estimatedRowHeight = 44
            tableView.register(ExpandableCell.self, forCellReuseIdentifier: "expandableCell")
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 5
        }
    
        override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "expandableCell", for: indexPath) as! ExpandableCell
            cell.delegate = self
            return cell
        }
    
        override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
                cell.isExpanded = true
            }
        }
    
        override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
            if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
                cell.isExpanded = false
            }
        }
    
        func expandableCellLayoutChanged(_ expandableCell: ExpandableCell) {
            refreshTableAfterCellExpansion()
        }
    
        func refreshTableAfterCellExpansion() {
            self.tableView.beginUpdates()
            self.tableView.setNeedsDisplay()
            self.tableView.endUpdates()
        }
    }
    
    protocol ExpandableCellDelegate: class {
        func expandableCellLayoutChanged(_ expandableCell: ExpandableCell)
    }
    
    class ExpandableCell: UITableViewCell {
        weak var delegate: ExpandableCellDelegate?
    
        fileprivate let stack = UIStackView()
        fileprivate let topView = UIView()
        fileprivate let bottomView = UIView()
    
        var isExpanded: Bool = false {
            didSet {
                bottomView.isHidden = !isExpanded
                delegate?.expandableCellLayoutChanged(self)
            }
        }
    
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
    
            selectionStyle = .none
    
            contentView.addSubview(stack)
            stack.addArrangedSubview(topView)
            stack.addArrangedSubview(bottomView)
    
            stack.translatesAutoresizingMaskIntoConstraints = false
            topView.translatesAutoresizingMaskIntoConstraints = false
            bottomView.translatesAutoresizingMaskIntoConstraints = false
    
            NSLayoutConstraint.activate([
                stack.topAnchor.constraint(equalTo: contentView.topAnchor),
                stack.leftAnchor.constraint(equalTo: contentView.leftAnchor),
                stack.rightAnchor.constraint(equalTo: contentView.rightAnchor),
                stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
    
                topView.heightAnchor.constraint(equalToConstant: 50),
    
                bottomView.heightAnchor.constraint(equalToConstant: 30),
                ])
    
            stack.axis = .vertical
            stack.distribution = .fill
            stack.alignment = .fill
            stack.spacing = 0
    
            topView.backgroundColor = .red
            bottomView.backgroundColor = .blue
            bottomView.isHidden = true
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = ExpandableCellViewController()
    

提交回复
热议问题