40

I'm able to expand and collapse cells but i wanna call functions (expand and collapse) inside UITableViewCell to change button title.

Iphone 5

import UIKit

class MyTicketsTableViewController: UITableViewController {

    var selectedIndexPath: NSIndexPath?
    var extraHeight: CGFloat = 100

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTicketsTableViewCell
        return cell
    }

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if(selectedIndexPath != nil && indexPath.compare(selectedIndexPath!) == NSComparisonResult.OrderedSame) {
            return 230 + extraHeight
        }

        return 230.0
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if(selectedIndexPath == indexPath) {
            selectedIndexPath = nil
        } else {
            selectedIndexPath = indexPath
        }

        tableView.beginUpdates()
        tableView.endUpdates()
    }
}

import UIKit

class MyTicketsTableViewCell: UITableViewCell {

    @IBOutlet weak var expandButton: ExpandButton!
    @IBOutlet weak var detailsHeightConstraint: NSLayoutConstraint!

    var defaultHeight: CGFloat!

    override func awakeFromNib() {
        super.awakeFromNib()

        defaultHeight = detailsHeightConstraint.constant

        expandButton.button.setTitle("TAP FOR DETAILS", forState: .Normal)
        detailsHeightConstraint.constant = 30
    }

    func expand() {
        UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveLinear, animations: {
            self.expandButton.arrowImage.transform = CGAffineTransformMakeRotation(CGFloat(M_PI * 0.99))
            self.detailsHeightConstraint.constant = self.defaultHeight
            self.layoutIfNeeded()

            }, completion: { finished in
                self.expandButton.button.setTitle("CLOSE", forState: .Normal)
        })
    }

    func collapse() {
        UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveLinear, animations: {
            self.expandButton.arrowImage.transform = CGAffineTransformMakeRotation(CGFloat(M_PI * 0.0))
            self.detailsHeightConstraint.constant = CGFloat(30.0)
            self.layoutIfNeeded()

            }, completion: { finished in
                self.expandButton.button.setTitle("TAP FOR DETAILS", forState: .Normal)
        })
    }

}

Ahmet Alsan
  • 624
  • 1
  • 5
  • 10
  • Please check this solution: [enter link description here](https://stackoverflow.com/questions/21396907/how-to-programmatically-increase-uitableview-cells-height-in-iphone/45424594#45424594) – Martin Deandreis Aug 08 '17 at 20:59
  • **Swift 4.2** I create an example expandable table view programmatically. - Expand cell appear and disappear with animation. - Title of selected section changing on expand. - views is in code and don't need story board. check this out in the link below: [Gist of expandable table view](https://gist.github.com/moraei/157e81bca16d039a8a0f2fe0fa986e02) – moraei Feb 25 '19 at 06:29

4 Answers4

39

If you want the cell to get physically bigger, then where you have your store IndexPath, in heightForRow: use:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if selectedIndexPath == indexPath {
      return 230 + extraHeight
    }
    return 230.0
}

Then when you want to expand one in the didSelectRow:

selectedIndexPath = indexPath
tableView.beginUpdates
tableView.endUpdates

Edit

This will make the cells animate themselves getting bigger, you dont need the extra animation blocks in the cell.

Edit 2

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        if(selectedIndexPath == indexPath) {
          selectedIndexPath = nil

          if let cell = tableView.cellForRowAtIndexPath(indexPath) as? MyTicketsTableViewCell {
            cell.collapse()
          }
          if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow:indexPath.row+1, section: indexPath.section) as? MyTicketsTableViewCell {
            cell.collapse()
          }
        } else {
          selectedIndexPath = indexPath

          if let cell = tableView.cellForRowAtIndexPath(indexPath) as? MyTicketsTableViewCell {
              cell.expand()
          }

          if let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow:indexPath.row+1, section: indexPath.section) as? MyTicketsTableViewCell {
             cell.expand()
          }
        }

        tableView.beginUpdates()
        tableView.endUpdates()
    }
Sean Lintern
  • 3,103
  • 22
  • 28
8

All you need is implement UITableView Delegate this way:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

By default, estimatedHeight is CGRectZero, when you set some value for it, it enables autoresizing (the same situation with UICollectionView), you can do even also so:

tableView?.estimatedRowHeight = CGSizeMake(50.f, 50.f); 

Then you need to setup you constraints inside your cell.

Check this post: https://www.hackingwithswift.com/read/32/2/automatically-resizing-uitableviewcells-with-dynamic-type-and-ns

Hope it helps)

Randika Vishman
  • 7,983
  • 3
  • 57
  • 80
Alex Kosyakov
  • 2,095
  • 1
  • 17
  • 25
  • This should be a comment. – Robotic Cat Apr 28 '16 at 14:26
  • 2
    Using UITableViewAutomaticDimension for estimatedHeight defeats the entire purpose of using estimatedHeight in the first place -- it's going to call auto layout on every indexPath in your tableView to calculate the height for the entire content, instead of using auto layout for just the visible cells, and estimatedHeight (which ideally is much much faster to calculate) for all the non-visible indexPaths. – Carl Lindberg Nov 27 '16 at 01:02
3

In MyTicketsTableViewController class, inside cellForRowAtIndexPath datasource method add target for the button.

cell.expandButton.addTarget(self, action: "expandorcollapsed:", forControlEvents: UIControlEvents.TouchUpInside)
Forge
  • 6,538
  • 6
  • 44
  • 64
Jeyamahesan
  • 1,101
  • 7
  • 15
  • 1
    I don't understand what is it for? – Ahmet Alsan Apr 29 '16 at 08:00
  • your calling expand and collapsing methods in tableviewcell class.instead of that, in your tableviewcontroller declare the expand,collapse method and in cellForRowAtIndexPath call the method like this – Jeyamahesan Apr 29 '16 at 08:06
1

I tried to implement lots of the given examples on this and other pages with similar questions, but none worked for me since I had to perform some logic in my custom cell (eg. hide unneeded UILables in CustomCell.swift when the cell is collapsed).

Here is the implementation that worked for me:

  1. Create a dictionary:

    private var _expandedCells: [IndexPath:Bool] = [:]
    
  2. Implement the heightForRowAt method:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return _expandedCells[indexPath] == nil ? 70 : _expandedCells[indexPath]! ? 150 : 70
    }
    
  3. Implement the didSelectRowAt method:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
        _expandedCells[indexPath] = _expandedCells[indexPath] == nil ? true : !_expandedCells[indexPath]!
    
        tableView.reloadRows(at: [indexPath], with: .fade)
    }
    
  4. Adjust your customCell:

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    
        guard let cell = cell as? YourCustomTableViewCell, let isExpanded = _expandedCells[indexPath] else { return }
    
        cell.set(expanded: isExpanded)
    }
    
Gasper J.
  • 481
  • 5
  • 11