Search code examples
iosanimationdidselectrowatindexpathuitableview

Swift - Animating When TableView Cell Selected (didSelectRowAtIndexPath)


I've been playing around trying to animate contents of my tableviewcell when it is selected, but i'm having issues. I had read some places that you cannot run animatewithduration within didSelectRowAtIndexPath or at least it doesn't animate if you do. It seems to be the case with the code I have below, the view moves but doesn't animate.

I have tried incorporating logic into willDisplayCell to monitor for the selection but to no avail, and so I would love it if someone is able to find the right solution for me because the answer is seemingly not available, despite a lot of searching:

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath)
    let cell = tableView.dequeueReusableCellWithIdentifier(currentCellDescriptor["cellIdentifier"] as! String, forIndexPath: indexPath) as! CustomCell
    let indexOfTappedRow = visibleRowsPerSection[indexPath.section][indexPath.row]
    if cellDescriptors[indexPath.section][indexOfTappedRow]["isExpandable"] as! Bool == true {
        if cellDescriptors[indexPath.section][indexOfTappedRow]["isExpanded"] as! Bool == false {


            // INTERESTING BIT: Animates cell contents to Right
            if currentCellDescriptor["cellIdentifier"] as! String == "CellHeader" {
                UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 12, options: .CurveLinear, animations: {
                    cell.headerTitleLeftConstraint.priority = 999
                    cell.headerTitleRightConstraint.priority = 1
                    cell.layoutIfNeeded()
                    }, completion: nil)
            }

       } else if cellDescriptors[indexPath.section][indexOfTappedRow]["isExpanded"] as! Bool == true {
           // MARK: Animates cell contents back to left
           if currentCellDescriptor["cellIdentifier"] as! String == "CellHeader" {
                UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 12, options: .CurveLinear, animations: {
                    cell.headerTitleLeftConstraint.priority = 1
                    cell.headerTitleRightConstraint.priority = 999
                    cell.layoutIfNeeded()
                     }, completion: nil)
                    }
            }

Solution

  • First, don't use dequeueReusableCellWithIdentifier here. It will use a cell not visible on screen and prepare to show it. What you want is cellForRowAtIndexPath which returns a cell already on screen at the given indexPath.

    Then I understand you want to play with 2 constraint and animate the layout changes. In order to do so, the animation should only contain layoutIfNeeded:

    cell.headerTitleLeftConstraint.priority = 999
    cell.headerTitleRightConstraint.priority = 1
    UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 12, options: .CurveLinear, animations: {
                    cell.layoutIfNeeded()
                    }, completion: nil)
    

    I'd also advice you to transfer this logic from the controller to your CustomCell class. For example use the selected attribute and the setSelected(animated: Bool) to handle the state change visually.