Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly override reloadRowsAtIndexPaths:withRowAnimation?

I would like to create a special animation for when I'm reloading the rows of a UITableView. The thing is I don't want to use this animation all the time, as I am sometimes using built-in animation for reloading the rows.

So how can I do this? By overriding reloadRowsAtIndexPaths:withRowAnimation in my own UITableView implementation? How?

Or maybe there is a better way to get my own animation while reloading a row?

like image 486
Nico Avatar asked Apr 16 '15 07:04

Nico


1 Answers

I think you should not override reloadRowsAtIndexPaths:withRowAnimation. Just implement a custom method reloadRowsWithMyAnimationAtIndexPaths:in UITableView's category and use it when it is needed.

But if you want to override this method in UITableView's subclass, you could do this:

- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths 
              withRowAnimation:(UITableViewRowAnimation)animation {
    if (self.useMyAnimation) 
        [self reloadRowsWithMyAnimationAtIndexPaths:indexPaths];
    else
        [super reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];
}

self.useMyAnimation is just a flag (BOOL property) that indicates what animation to use. Set this flag before reload operation.

For 2 or more customAnimations you could implement enum:

enum MyTableViewReloadAnimationType {
    case None
    case First
    case Second
    case Third
}

Then make a MyTableViewReloadAnimationType property (for example, reloadAnimationType) and select an appropriate animation method with switch:

    var reloadAnimationType = MyTableViewReloadAnimationType.None

    override func reloadRowsAtIndexPaths(indexPaths: [AnyObject], withRowAnimation animation: UITableViewRowAnimation) {
        switch self.reloadAnimationType {
        case .None:
            super .reloadRowsAtIndexPaths(indexPaths, withRowAnimation:animation)
        default:
            self .reloadRowsAtIndexPaths(indexPaths, withCustomAnimationType:self.reloadAnimationType)
        }
    }

    func reloadRowsAtIndexPaths(indexPaths: [AnyObject], withCustomAnimationType animationType: MyTableViewReloadAnimationType) {
        switch animationType {
        case .First:
            self .reloadRowsWithFirstAnimationAtIndexPaths(indexPaths)
        case .Second:
            self .reloadRowsWithSecondAnimationAtIndexPaths(indexPaths)
        case .Third:
            self .reloadRowsWithThirdAnimationAtIndexPaths(indexPaths)
        }
    }

You could call the custom method reloadRowsAtIndexPaths:withCustomAnimationType: directly:

self.tableView .reloadRowsAtIndexPaths([indexPath], withCustomAnimationType: MyTableViewReloadAnimationType.First)

Inside the custom method you need to get a current cell and a new cell with method of dataSource:

func reloadRowsWithFirstAnimationAtIndexPaths(indexPaths: [AnyObject]) {
    for indexPath in indexPaths {
        var currentCell = self .cellForRowAtIndexPath(indexPath as! NSIndexPath)
        var newCell = self.dataSource .tableView(self, cellForRowAtIndexPath: indexPath as! NSIndexPath)
        var newCellHeight = self.delegate .tableView(self, heightForRowAtIndexPath: indexPath)
        var frame: CGRect = currentCell.frame
        frame.size.height = newCellHeight
        newCell.frame = frame
        self .replaceCellWithFirstAnimation(currentCell!, withAnotherCell: newCell);
    }
}

func replaceCellWithFirstAnimation(firstCell : UITableViewCell, withAnotherCell secondCell: UITableViewCell) {
    var cellsSuperview = firstCell.superview!
    //make this with animation
    firstCell .removeFromSuperview()
    cellsSuperview .addSubview(secondCell)
}

You need to handle a situation when newCell's height > or < then currentCell's height. All other cells frames must be recalculated. I think it could be done with beginUpdates and endUpdates methods. Call them before the manipulation with cells.

like image 198
Vlad Avatar answered Nov 16 '22 03:11

Vlad