2つのモードがあるUITableViewがあります。モードを切り替えると、セクションごとに異なる数のセクションとセルがあります。理想的には、テーブルが拡大または縮小するときにクールなアニメーションを作成します。
ここに私が試したコードがありますが、何もしません:
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.5];
[self.tableView reloadData];
[UIView commitAnimations];
私はこれをどのように行うことができますか?
実際、それは非常に簡単です:
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
ドキュメント から:
このメソッドを呼び出すと、Table Viewは指定されたセクションの新しいセルをデータソースに要求します。テーブルビューは、古いセルをアニメーション化するときに新しいセルの挿入をアニメーション化します。
あなたが使用することがあります:
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
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
を変更します。
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のリファレンス
あなたはあなたのデータ構造を更新するだけでいいと信じています:
[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
これらの回答はすべて、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];
これにアプローチする方法は、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]
(または何でも)をチェックすることでセクションと行の正しい新しいセットを返す限り、これはあなたが探している効果を達成します。
一番上の答えにコメントすることはできませんが、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で導入されました。)
Swift 4 @dmarnel回答のバージョン:
tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
Swift Implementation:
let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
Swift 4の場合
tableView.reloadSections([0], with: UITableView.RowAnimation.fade)
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つだけではありません。
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)
})
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に変更して見やすくすることも、他の利用可能なアニメーションのリストから選択することもできます。
独自のカスタムアニメーションをUITableViewセルに追加する場合は、使用します
[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];
可視セルの配列を取得します。次に、カスタムアニメーションを各セルに追加します。
スムーズなカスタムセルアニメーションについて投稿したこの要点をご覧ください。 https://Gist.github.com/floprr/1b7a58e4a18449d962bd
私の場合、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:」を使用してクラッシュを回避する必要があります。