【问题标题】:Table view cell load animation one after another表格视图单元格加载动画一个接一个
【发布时间】:2016-01-29 08:57:46
【问题描述】:

我需要为表格视图行的加载设置动画。当表重新加载数据时,我需要一行接一个地从左侧进入。我怎样才能做到这一点?

【问题讨论】:

    标签: ios uitableview animation cell


    【解决方案1】:

    斯威夫特 4

    添加这个可爱的小扩展

    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
            }
        }
    }
    

    然后,使用“tableView.reloadWithAnimation()”代替“tableView.reloadData()”

    【讨论】:

    • 好一个!谢谢。
    【解决方案2】:

    这是我的 Swift 3 解决方案,用于逐个显示单元格。 它的好处是它们仅在第一次加载时加载,并且仅用于最初显示的单元格(当用户向下滚动时不会运行)。

    享受:)

    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)
        }
    }
    

    【讨论】:

    • 太棒了!像魅力一样工作!
    【解决方案3】:

    在您的 tableview 委托中,

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

    把这个从下到上的淡入翻译动画(简体自Anbu.Karthik回答),

        //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];
    

    为了更好的用户体验,建议每行只播放一次动画一次,直到表格视图被解除分配。

    将上面的代码放入

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

    ------- 斯威夫特 ------------------------------------ -------------------------------------------------- ---------------------------------------

    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()
        }
    }
    

    【讨论】:

    • 我想要两个动画两个默认自定义单元格。最初一个单元格显示在 tableview 中,10 秒后另一个单元格将出现在 tableview 上。但是现在 tableview 顶部的第二个单元格和第一个细胞向下移动。如何实现这一点。如果您有任何想法,请帮助我。
    • 你可以使用 [UIView animateWithDuration:0.5 delay:10.0 options: UIViewAnimationOptionTransitionCrossDissolve animations:^{ // 动画开始 } completion:nil]; }];
    【解决方案4】:

    提供的解决方案都没有帮助我,所以我想出了自己的解决方案。这是一个通用的小类,可用于将动画链接在一起并一个接一个地播放它们。它的语法类似于 UIView.animate() 的语法,一旦被调用,就会将动画异步排队,然后按照添加顺序按顺序开始执行队列:

    斯威夫特 4.1

    ChainedAnimationsQueue.swift

    import UIKit
    import Foundation
    
    class ChainedAnimationsQueue {
    
      private var playing = false
      private var animations = [(TimeInterval, () -> Void, () -> Void)]()
    
      init() {
      }
    
      /// Queue the animated changes to one or more views using the specified duration and an initialization block.
      ///
      /// - Parameters:
      ///   - duration: The total duration of the animations, measured in seconds. If you specify a negative value or 0, the changes are made without animating them.
      ///   - initializations: A block object containing the changes to commit to the views to set their initial state. This block takes no parameters and has no return value. This parameter must not be NULL.
      ///   - animations: A block object containing the changes to commit to the views. This is where you programmatically change any animatable properties of the views in your view hierarchy. This block takes no parameters and has no return value. This parameter must not be NULL.
      func queue(withDuration duration: TimeInterval, initializations: @escaping () -> Void, animations: @escaping () -> Void) {
        self.animations.append((duration, initializations, animations))
        if !playing {
          playing = true
          DispatchQueue.main.async {
            self.next()
          }
        }
      }
    
      private func next() {
        if animations.count > 0 {
          let animation = animations.removeFirst()
          animation.1()
          UIView.animate(withDuration: animation.0, animations: animation.2, completion: { finished in
            self.next()
          })
        } else {
          playing = false
        }
      }
    }
    

    示例用法:

    var animationsQueue = ChainedAnimationsQueue()
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
      cell.alpha = 0.0
      animationsQueue.queue(withDuration: 0.2, initializations: {
        cell.layer.transform = CATransform3DTranslate(CATransform3DIdentity, cell.frame.size.width, 0, 0)
      }, animations: {
        cell.alpha = 1.0
        cell.layer.transform = CATransform3DIdentity
      })
    }
    

    【讨论】:

      【解决方案5】:

      斯威夫特 4

      我在 UITableView 上做了一个快速扩展来动画单元格:

      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")
          })
      

      扩展看起来像这样:

      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
            }
          }
        }
      }
      

      【讨论】:

      • 很好的答案。谢谢。完美运行。
      【解决方案6】:

      这是一个简单漂亮的淡入淡出动画,我主要用在我的 tableview 中

      func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
              cell.alpha = 0
              UIView.animate(withDuration: 1) {
                  cell.alpha = 1.0
              }
          }
      

      【讨论】:

      • 这会同时淡入所有单元格。
      【解决方案7】:

      tableView:willDisplayCell:forRowAtIndexPath 方法将在每次显示单元格时被调用,并且由于它们被同时查看,这意味着它们在不同的线程中被调用并且你不能告诉 iOS SDK 调用此方法为顺序。所以我认为获得你想要的东西的方法是在每个单元格显示时为它设置一个延迟。

      -(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
          }];
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-30
        • 1970-01-01
        • 2023-02-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多