web-dev-qa-db-ja.com

テーブルビューセルの読み込みアニメーション

テーブルビューの行の負荷をアニメーション化する必要があります。テーブルがデータを再ロードするとき、私は行が左から次々と入る必要があります。どうすればこれを達成できますか?

14

テーブルビューデリゲートで、

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

UXを向上させるために、テーブルビューの割り当てが解除されるまで、アニメーションは各行に対してonceのみを再生することをお勧めします。

上記のコードを

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

Swift 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.reloadData()」の代わりに「tableView.reloadWithAnimation()」を使用します

28
Alfi

ここに私のSwift 3セルを1つずつ表示するための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)
    }
}
25
chikko

提供されたソリューションはどれも役に立たなかったので、自分で考えました。以下は、アニメーションをチェーンして次々に再生するために使用できる少し汎用的なクラスです。構文はUIView.animate()の構文に似ており、一度呼び出されると、非同期的にアニメーションをキューに入れ、追加された順序で順番にキューの実行を開始します。

Swift 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
  })
}
2
Omid Ariyan

これはシンプルな美しいフェードアニメーションで、主にテーブルビューで使用しました

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

Swift 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
      }
    }
  }
}
1
billgert

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
    }];
}
0
Mehdi