web-dev-qa-db-ja.com

変更時にUITableViewアニメーションのreloadDataを使用する

2つのモードがあるUITableViewがあります。モードを切り替えると、セクションごとに異なる数のセクションとセルがあります。理想的には、テーブルが拡大または縮小するときにクールなアニメーションを作成します。

ここに私が試したコードがありますが、何もしません:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

私はこれをどのように行うことができますか?

168
Chris Butler

実際、それは非常に簡単です:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

ドキュメント から:

このメソッドを呼び出すと、Table Viewは指定されたセクションの新しいセルをデータソースに要求します。テーブルビューは、古いセルをアニメーション化するときに新しいセルの挿入をアニメーション化します。

392
dmarnel

あなたが使用することがあります:

Objective-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

スイフト

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

Swift

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

面倒なし。 :D

クールな効果に必要なUIViewAnimationOptionTransitionsを使用することもできます。

  • TransitionNone
  • TransitionFlipFromLeft
  • TransitionFlipFromRight
  • TransitionCurlUp
  • TransitionCurlDown
  • TransitionCrossDissolve
  • TransitionFlipFromTop
  • TransitionFlipFromBottom
239
Kenn Cal

CATransitionクラスを使用して自由度を高めます。

フェージングに限らず、動きもできます。


例えば:

QuartzCoreをインポートすることを忘れないでください)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

typeなど、必要に応じてkCATransitionFadeを変更します。

Swiftでの実装:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

CATransitionのリファレンス

69
code ninja

あなたはあなたのデータ構造を更新するだけでいいと信じています:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

また、「withRowAnimation」は厳密にはブール値ではなく、アニメーションスタイルです。

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle
59

これらの回答はすべて、1つのセクションのみでUITableViewを使用していることを前提としています。

複数のセクションを使用している状況を正確に処理するには:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(注:セクションが0個以上あることを確認してください!)

もう1つの注意点は、このコードでデータソースを同時に更新しようとすると、NSInternalInconsistencyExceptionが発生する可能性があることです。この場合、次のようなロジックを使用できます。

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];
23
diadyne

これにアプローチする方法は、tableViewに行とセクションを削除して追加するように指示することです

insertRowsAtIndexPaths:withRowAnimation:deleteRowsAtIndexPaths:withRowAnimation:insertSections:withRowAnimation:およびdeleteSections:withRowAnimation:

uITableViewのメソッド。これらのメソッドを呼び出すと、テーブルは要求したアイテムを入出力し、それ自体でreloadDataを呼び出して、このアニメーションの後に状態を更新できるようにします。この部分は重要です-すべてをアニメーション化しても、テーブルのdataSourceによって返されるデータを変更しない場合、アニメーションの完了後に行が再び表示されます。

したがって、アプリケーションフローは次のようになります。

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

テーブルのdataSourceメソッドが[self tableIsInSecondState](または何でも)をチェックすることでセクションと行の正しい新しいセットを返す限り、これはあなたが探している効果を達成します。

17
iKenndac

一番上の答えにコメントすることはできませんが、Swift実装は次のようになります。

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

reloadSectionsの最初の引数には、更新するセクションをいくつでも含めることができます。

ドキュメントから利用可能な他のアニメーション: https://developer.Apple.com/reference/uikit/uitableviewrowanimation

fade挿入または削除された行は、テーブルビューにフェードインまたはフェードアウトします。

right挿入された行は右からスライドします。削除された行は右にスライドします。

left挿入された行は左からスライドします。削除された行は左にスライドします。

top挿入された行は上からスライドします。削除された行は、上部に向かってスライドします。

bottom挿入された行は下からスライドします。削除された行は下に向かってスライドします。

case none挿入または削除された行はデフォルトのアニメーションを使用します。

middleテーブルビューは、古いセルと新しいセルを、それらが占めていたまたは占有するスペースの中央に維持しようとします。 iPhone 3.2で利用可能。

automaticテーブルビューは、適切なアニメーションスタイルを選択します。 (iOS 5.0で導入されました。)

16

Swift 4 @dmarnel回答のバージョン:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
10
chengsam

Swift Implementation:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
9

Swift 4の場合

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)
5
Claus
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];
1
Mayur Sardana

すべてのセクションをリロードするカスタム期間の1つだけではありません。

UIView.animateのユーザーdurationパラメーターは、カスタム期間を設定します。

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})
1
JPetric

SwiftでreloadData()を使用せずにアニメーション化するには、次のようにします(バージョン2.2以降)。

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

アニメーションの終了後にreloadData()を呼び出す必要がある場合、次のようにCATransactionの変更を受け入れることができます。

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

行を削除する場合のロジックが示されていますが、行を追加する場合にも同じ考え方が機能します。また、アニメーションをUITableViewRowAnimation.Leftに変更して見やすくすることも、他の利用可能なアニメーションのリストから選択することもできます。

1
Vitalii

独自のカスタムアニメーションをUITableViewセルに追加する場合は、使用します

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

可視セルの配列を取得します。次に、カスタムアニメーションを各セルに追加します。

スムーズなカスタムセルアニメーションについて投稿したこの要点をご覧ください。 https://Gist.github.com/floprr/1b7a58e4a18449d962bd

1
flopr

私の場合、Tableviewにさらに10行追加して(「結果をさらに表示」タイプの機能のために)、次のことを行いました。

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

ほとんどの場合、「self.numberOfRows」の代わりに、通常はテーブルビューのオブジェクトの配列のカウントを使用します。したがって、このソリューションが適切に機能することを確認するには、「arrayOfIndexPaths」は、挿入される行のインデックスパスの正確な配列である必要があります。このインデックスパスのいずれかに行が存在する場合、コードがクラッシュする可能性があるため、これらのインデックスパスにメソッド「reloadRowsAtIndexPaths:withRowAnimation:」を使用してクラッシュを回避する必要があります。

1
Lucas Chwe