Table view cell load animation one after another

后端 未结 7 982
面向向阳花
面向向阳花 2021-01-31 05:32

I need to animate the load of the table view rows. When the table reloads the data I need the rows get in from the left one after another. How can I achieve this?

相关标签:
7条回答
  • 2021-01-31 06:05

    In your tableview delegate,

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    

    Put this bottom-to-top fade-in translation animation (Simplified from Anbu.Karthik answer),

        //1. Define the initial state (Before the animation)
        cell.transform = CGAffineTransformMakeTranslation(0.f, CELL_HEIGHT);
        cell.layer.shadowColor = [[UIColor blackColor]CGColor];
        cell.layer.shadowOffset = CGSizeMake(10, 10);
        cell.alpha = 0;
    
        //2. Define the final state (After the animation) and commit the animation
        [UIView beginAnimations:@"rotation" context:NULL];
        [UIView setAnimationDuration:0.5];
        cell.transform = CGAffineTransformMakeTranslation(0.f, 0);
        cell.alpha = 1;
        cell.layer.shadowOffset = CGSizeMake(0, 0);
        [UIView commitAnimations];
    

    For better UX, it is advised that the animation should only be played once for each row, until the table view is dealloc-ed.

    Put the above code in

    if (![self.shownIndexes containsObject:indexPath]) {
        [self.shownIndexes addObject:indexPath];
    
        // Your animation code here.
    }
    

    ------- Swift -----------------------------------------------------------------------------------------------------------------

    var shownIndexes : [IndexPath] = []
    let CELL_HEIGHT : CGFloat = 40
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if (shownIndexes.contains(indexPath) == false) {
            shownIndexes.append(indexPath)
    
            cell.transform = CGAffineTransform(translationX: 0, y: CELL_HEIGHT)
            cell.layer.shadowColor = UIColor.black.cgColor
            cell.layer.shadowOffset = CGSize(width: 10, height: 10)
            cell.alpha = 0
    
            UIView.beginAnimations("rotation", context: nil)
            UIView.setAnimationDuration(0.5)
            cell.transform = CGAffineTransform(translationX: 0, y: 0)
            cell.alpha = 1
            cell.layer.shadowOffset = CGSize(width: 0, height: 0)
            UIView.commitAnimations()
        }
    }
    
    0 讨论(0)
  • 2021-01-31 06:08

    Swift 4

    Add this little cute extension

    extension UITableView {    
    
        func reloadWithAnimation() {
            self.reloadData()
            let tableViewHeight = self.bounds.size.height
            let cells = self.visibleCells
            var delayCounter = 0
            for cell in cells {
                cell.transform = CGAffineTransform(translationX: 0, y: tableViewHeight)
            }
            for cell in cells {
                UIView.animate(withDuration: 1.6, delay: 0.08 * Double(delayCounter),usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
                    cell.transform = CGAffineTransform.identity
                }, completion: nil)
                delayCounter += 1
            }
        }
    }
    

    Then, instead of "tableView.reloadData()", use "tableView.reloadWithAnimation()"

    0 讨论(0)
  • 2021-01-31 06:11

    Here's my Swift 3 solution for displaying the cells one by one. what's nice about it is that they load only at first load time, and only for the initially displayed cells (will not run when user scrolls down).

    Enjoy :)

    private var finishedLoadingInitialTableCells = false
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    
        var lastInitialDisplayableCell = false
    
        //change flag as soon as last displayable cell is being loaded (which will mean table has initially loaded)
        if yourTableData.count > 0 && !finishedLoadingInitialTableCells {
            if let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows,
                let lastIndexPath = indexPathsForVisibleRows.last, lastIndexPath.row == indexPath.row {
                lastInitialDisplayableCell = true
            }
        }
    
        if !finishedLoadingInitialTableCells {
    
            if lastInitialDisplayableCell {
                finishedLoadingInitialTableCells = true
            }
    
            //animates the cell as it is being displayed for the first time
            cell.transform = CGAffineTransform(translationX: 0, y: self.rowHeight/2)
            cell.alpha = 0
    
            UIView.animate(withDuration: 0.5, delay: 0.05*Double(indexPath.row), options: [.curveEaseInOut], animations: {
                cell.transform = CGAffineTransform(translationX: 0, y: 0)
                cell.alpha = 1
            }, completion: nil)
        }
    }
    
    0 讨论(0)
  • 2021-01-31 06:16

    tableView:willDisplayCell:forRowAtIndexPath method will be called each time a cell is going to be shown, and since they are getting viewed at the same time it means that they are getting called in different threads and you can't tell iOS SDK to call this method for sequentially. So I think the way to get what you want is to set a delay for each cell when it is being showed.

    -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell*)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
        CGFloat delay = indexPath.row * yourSupposedAnimationDuration;
        [UIView animateWithDuration:yourSupposedAnimationDuration delay:delay options:UIViewAnimationOptionCurveEaseIn animations:^{  
            //Your animation code
        }completion:^(BOOL finished) {  
            //Your completion Code
        }];
    }
    
    0 讨论(0)
  • 2021-01-31 06:24

    This is simple beautiful fade animation Which I mostly I used in my tableview

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            cell.alpha = 0
            UIView.animate(withDuration: 1) {
                cell.alpha = 1.0
            }
        }
    
    0 讨论(0)
  • 2021-01-31 06:29

    Swift 4

    I made a quick extension on UITableView to animate cells:

    tableView.reloadData() // To make sure tableView.visibleCells is not empty
    
    tableView.animateCells(
          cells: tableView.visibleCells,
          duration: 0.3,
          delay: 0.5,
          dampingRatio: 0.8,
          configure: { cell -> (prepare: () -> Void, animate: () -> Void)? in
            guard let customCell = cell as? CustomCell else { return nil }
            let preparations = {
              customCell.iconImageView.alpha = 0
            }
            let animations = {
              customCell.iconImageView.alpha = 1
            }
            return (preparations, animations)
        }, completion: {
          print("Cell animations are completed")
        })
    

    The extension looks like this:

    extension UITableView {
      func animateCells<Cell: UITableViewCell>(cells: [Cell],
                                               duration: TimeInterval,
                                               delay: TimeInterval = 0,
                                               dampingRatio: CGFloat = 0,
                                               configure: @escaping (Cell) -> (prepare: () -> Void, animate: () -> Void)?,
                                               completion: @escaping () -> Void) {
        var cellDelay: TimeInterval = 0
        var completionCount: Int = 0
    
        for cell in cells {
          if let callbacks = configure(cell) {
            callbacks.prepare()
    
            let animator = UIViewPropertyAnimator(duration: duration, dampingRatio: dampingRatio)
    
            animator.addAnimations(callbacks.animate)
    
            let completionTime = cellDelay + (duration * TimeInterval(dampingRatio))
    
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + completionTime) {
              completionCount += 1
              if completionCount == cells.count {
                completion()
              }
            }
    
            animator.startAnimation(afterDelay: cellDelay)
    
            cellDelay += delay
          } else {
            completionCount += 1
          }
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题