Search code examples
iosswiftuitableviewuibuttonxib

Custom UIButton TableView not responding


I made a custom UIButton which have a collapse UITableView in it. Once you tap the button the table view height constraint change and the table view opens with collapse effect. I managed to create delegate to the button which provide the table's data but I can't get the didSelectRow and scroll the tableView. I think it may related to the need to enlarge the button frame when the tableView collapse but I didn't managed to do that.

Here's the custom UIButton:

CollapseButton.swift
Created by  Matan Levi on 21/12/2020.


import UIKit

protocol CollapseButtonDelegate
{
var options : [String] { get }
func didSelectRow(tableView: UITableView, indexPath: IndexPath)
}

@IBDesignable class CollapseButton: UIButton {

@IBOutlet weak var btnTableViewOutlet: UITableView!
@IBOutlet weak var btnCollapseHeight: NSLayoutConstraint!

let open = CGFloat(113)
let close = CGFloat.zero
var isOpen = false
var delegate : CollapseButtonDelegate?

//  init used if the view is created programmatically
override init(frame: CGRect) {
    super.init(frame: frame)
    self.customInit()
}

//  init used if the view is created through IB
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    self.customInit()
}

override func awakeAfter(using aDecoder: NSCoder) -> Any? {
      guard subviews.isEmpty else { return self }
    let view = UINib(nibName: "CollapseButton", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }
//  Do custom initialization here
private func customInit()
{

}


@IBAction func collapseBtn(_ sender: UIButton) {
    self.btnTableViewOutlet.addBorder()
    UIView.animate(withDuration: 1) {
        self.btnCollapseHeight.constant = self.isOpen ? self.close : self.open
        sender.imageView?.transform = self.isOpen ? CGAffineTransform.identity : CGAffineTransform(rotationAngle: .pi)
        self.layoutIfNeeded()

    }
    isOpen = !isOpen
}
}

extension CollapseButton : UITableViewDelegate, UITableViewDataSource
{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return delegate?.options.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
    cell.textLabel?.text = delegate?.options[indexPath.row]
    cell.backgroundColor = .green
    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    delegate?.didSelectRow(tableView: tableView, indexPath: indexPath)
}

}

And here's the button implementation:

extension PortfolioViewController : CollapseButtonDelegate
{
func didOpenCollapse() {
    accountBtnOutlet.setNeedsUpdateConstraints()
    accountBtnOutlet.addBorder()
}

var options: [String] {
    return FakeDataSupplier.shared.getAccountsData()
}

func didSelectRow(tableView: UITableView, indexPath: IndexPath) {
    print(indexPath.row)
}
}

I tried:

1.Checking user interactions enabled 2.Checking that the delegate and data source connected 3.Checking that there's nothing above the UITableView in the ui debugger

Any suggestion would be very appreciated

EDIT

Added screenshot:

Button Image


Solution

  • So the actual solution went that way: at first iv'e changed my class to UIView, which make things way more convenient in terms of adding more views or tables in my case. After that i made delegate for the opening of the table and in the viewController that using the button i made an height constraint outlet to the button and updated it when that button open the collapse table. Thanks to @DonMag for guiding me to investigate the solution.

    I will try make it more simple and easy to use but until then, here's the semi final buttonView class:

    //
    //  CollapseView.swift
    //  IBITrade
    //
    //  Created by  Matan Levi IBI on 22/12/2020.
    //
    
    import UIKit
    
    protocol CollapseViewDelegate
    {
      func setTableViewOptions(collapseView : CollapseView) -> [String]
      func didSelectRow(collapseView : CollapseView, tableView: UITableView, indexPath: IndexPath)
      func isCollapseOpen(collapseView : CollapseView, isOpen : Bool)
    }
    
    @IBDesignable class CollapseView: UIView {
    
    @IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet weak var collapseBtnOutlet: UIButton!
    @IBOutlet weak var collapseTableViewOutlet: UITableView!
    
    public var buttonTitle: String = "" {
            didSet {
                self.collapseBtnOutlet.setTitle(buttonTitle, for: .normal)
            }
        }
    
    var delegate : CollapseViewDelegate?
    let open = CGFloat(113)
    let close = CGFloat.zero
    var isOpen = false
    
    //  init used if the view is created programmatically
    let nibName = "CollapseView"
    var contentView:UIView?
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    func commonInit() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
        
    }
    func loadViewFromNib() -> UIView? {
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
    
    
    @IBAction func openCloseTable(_ sender: UIButton) {
        collapseTableViewOutlet.addBorder()
        UIView.animate(withDuration: 1) { [self] in
            self.tableViewHeightConstraint.constant = self.isOpen ? self.close : self.open
            sender.imageView?.transform = self.isOpen ? CGAffineTransform.identity : CGAffineTransform(rotationAngle: .pi)
            delegate?.isCollapseOpen(collapseView: self, isOpen: isOpen)
            self.layoutIfNeeded()
        }
        
        isOpen = !isOpen
      }
    
    }
    extension CollapseView : UITableViewDelegate, UITableViewDataSource
      {
       func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return delegate?.setTableViewOptions(collapseView: self).count ?? 0
      }
    
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
        cell.textLabel?.text = delegate?.setTableViewOptions(collapseView: self)[indexPath.row]
        cell.backgroundColor = .green
        return cell
      }
    
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        delegate?.didSelectRow(collapseView: self, tableView: tableView, indexPath: indexPath)
      }
    
    }