2

This is what I currently have

Section Slide Down Animation

This is the code extending UITableViewDelegate

extension IngredientsViewController: UITableViewDelegate {
    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {

        return 50
    }

    func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 0
    }

    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if self.collapses[indexPath.section] == true {
            return 0
        }
        return 50
    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 50))
        headerView.backgroundColor = UIColor(hexString: AppConfiguration.UIColorCode["orange"]!, alpha: 0.7)

        headerView.tag = section

        let headerString = UILabel(frame: CGRect(x: 12, y: 0, width: tableView.frame.size.width-24, height: 50)) as UILabel
        headerString.text = (self.stores[section] as! Store).name!.uppercaseString
        headerString.textColor = UIColor.whiteColor()
        headerString.font = FontCollection.tableHeaderFont
        headerView .addSubview(headerString)

        let headerTapped = UITapGestureRecognizer (target: self, action:"sectionHeaderTapped:")
        headerView .addGestureRecognizer(headerTapped)

        return headerView
    }

    func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        if self.deselecting {
            self.deselecting = false
            return
        }
        if self.selectedIndexPath.indexOf(indexPath) != nil {
            cell.selected = true
        }
    }

    func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
        self.selectedIndexPath.removeAtIndex(self.selectedIndexPath.indexOf(indexPath)!)
        self.deselecting = true
    }

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        self.selectedIndexPath.append(indexPath)
    }

    func sectionHeaderTapped(recognizer: UITapGestureRecognizer) {

        let indexPath : NSIndexPath = NSIndexPath(forRow: 0, inSection:(recognizer.view?.tag as Int!)!)
        if (indexPath.row == 0) {
            self.collapses[indexPath.section] = !self.collapses[indexPath.section]

            //reload specific section animated
            let range = NSMakeRange(indexPath.section, 1)
            let sectionToReload = NSIndexSet(indexesInRange: range)
            self.tableView.reloadSections(sectionToReload, withRowAnimation: .Fade)
        }
    }
}

My questions

  1. The animation feels like each of the cell is fading in/out by itself. I'd rather have the whole section slide up/down. Been looking around but doesn't find much example of this. And I don't understand why the section header is having the white highlight on touch?
  2. To maintain the selected between collapsing and expanding, I'm storing the selection in an array and use willDisplayCell to determine the selection state upon rendering the cell. Is this the right and most efficient approach?
  3. Using the above code, when a cell is selected, collapse the section that cell belongs to, expand that section, then the said cell become unresponsive to didSelect and didDeselect (while unselected cells are still responsive). Any ideas why? Update for this issue below.

Thank you.

------ UPDATE ------

The above approach I used for rendering selected state with collapsed cell is flawed (issue #3). The below code will make the cell not interactive anymore

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if self.deselecting {
        self.deselecting = false
        return
    }
    if self.selectedIndexPath.indexOf(indexPath) != nil {
        cell.selected = true
    }
}

Instead of that, one should do this

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if self.selectedIndexPath.indexOf(indexPath) != nil {
        tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
    }
}
Alvin Nguyen
  • 374
  • 2
  • 14
  • I'm staring at your example trying to figure out the white highlight you mentioned, and I can't for the life of me imagine what it is. I think I'll return to this question tomorrow to see if someone else has managed to shed some light! – TwoStraws Dec 13 '15 at 22:29

1 Answers1

1

Apple has a great piece of sample code that I believe does exactly what you want: https://developer.apple.com/library/ios/samplecode/TableViewUpdates/Introduction/Intro.html. Summary: you use table header views to insert and remove rows when tapped, and UITableView can animate all that for you.

This StackOverflow answer contains a Swift-ified version of the Apple code, if that's what you'd prefer.

Either way, this approach is significantly more efficient than some implementations I've seen where people hide and show a UIStackView in their rows.

Community
  • 1
  • 1
TwoStraws
  • 12,862
  • 3
  • 57
  • 71
  • Thank for pointing me this way. So it's adding/removing instead of just not rendering like the approach I used. I'll try this out, maybe this will solve all the 1, 2, 3 problems. Will keep you posted. – Alvin Nguyen Dec 13 '15 at 23:37