web-dev-qa-db-fra.com

Avoir une reloadData pour une UITableView animer lors du changement

J'ai un UITableView qui a deux modes. Lorsque nous basculons entre les modes, j'ai un nombre différent de sections et de cellules par section. Idéalement, il ferait une bonne animation lorsque la table s'agrandit ou diminue.

Voici le code que j'ai essayé, mais ça ne fait rien:

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

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

Des idées sur comment je pourrais faire ça?

164
Chris Butler

En fait, c'est très simple:

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

De la documentation :

L'appel de cette méthode entraîne l'affichage par la vue tabulaire de sa source de données nouvelles cellules pour les sections spécifiées. La vue tableau anime le fichier insertion de nouvelles cellules dans l'animation des anciennes cellules.

384
dmarnel

Vous voudrez peut-être utiliser:

Objectif c

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

Rapide

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

Swift 3

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

Pas de soucis. :RÉ

Vous pouvez également utiliser l'une des variables UIViewAnimationOptionTransitions que vous souhaitez pour des effets plus froids:

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

Avoir plus de liberté en utilisant la classe CATransition.

Il ne se limite pas à la décoloration, mais peut aussi faire des mouvements.


Par exemple:

(n'oubliez pas d'importer 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"];

Modifiez la type pour qu'elle corresponde à vos besoins, par exemple kCATransitionFade etc.

Mise en œuvre dans 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()

Référence pour CATransition

65
code ninja

Je crois que vous pouvez simplement mettre à jour votre structure de données, puis:

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

En outre, "withRowAnimation" n'est pas exactement un booléen, mais un style d'animation:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle
59
Tiago Fael Matos

Toutes ces réponses supposent que vous utilisez un UITableView avec une seule section.

Pour gérer avec précision les situations dans lesquelles vous avez plusieurs sections, utilisez:

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

(Remarque: vous devez vous assurer que vous avez plus de 0 sections!)

Une autre chose à noter est que vous pouvez rencontrer une exception NSInternalInconsistencyException si vous essayez de mettre à jour simultanément votre source de données avec ce code. Si tel est le cas, vous pouvez utiliser une logique similaire à celle-ci:

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

La solution consiste à indiquer à la tableView de supprimer et d’ajouter des lignes et des sections avec le

insertRowsAtIndexPaths:withRowAnimation:, deleteRowsAtIndexPaths:withRowAnimation:, insertSections:withRowAnimation: et deleteSections:withRowAnimation:

méthodes de UITableView. Lorsque vous appelez ces méthodes, la table animera les éléments que vous avez demandés, puis appelera reloadData sur elle-même afin que vous puissiez mettre à jour l'état après cette animation. Cette partie est importante: si vous animez tout en évitant de modifier les données renvoyées par la source de données de la table, les lignes réapparaîtront à la fin de l'animation. 

Votre flux d’application serait donc:

[self setTableIsInSecondState:YES];

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

Tant que les méthodes dataSource de votre table renvoient le nouvel ensemble correct de sections et de lignes en cochant [self tableIsInSecondState] (ou autre), vous obtiendrez l'effet que vous recherchez.

17
iKenndac

Je ne peux pas commenter la réponse principale, mais une implémentation de Swift serait: 

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

vous pouvez inclure autant de sections que vous souhaitez mettre à jour dans le premier argument de reloadSections.

Autres animations disponibles dans les documents: https://developer.Apple.com/reference/uikit/uitableviewrowanimation

fade La ou les lignes insérées ou supprimées apparaissent ou disparaissent en fondu dans la vue tabulaire.

right La ou les lignes insérées entrent par la droite; la ou les lignes supprimées glissent vers la droite.

left La ou les lignes insérées entrent par la gauche; la ou les lignes supprimées glissent vers la gauche.

top La ou les lignes insérées entrent par le haut; la ou les lignes supprimées glissent vers le haut.

bottom La ou les lignes insérées entrent par le bas; la ou les lignes supprimées glissent vers le bas.

case none Les lignes insérées ou supprimées utilisent les animations par défaut.

middle La vue de tableau tente de garder les anciennes et les nouvelles cellules centrées dans l'espace qu'elles occupaient ou occuperont. Disponible dans l'iPhone 3.2.

automatic La vue en tableau choisit un style d'animation approprié pour vous. (Introduit dans iOS 5.0.)

16
Christopher Larsen

Mise en œuvre rapide:

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

Swift 4 version pour la réponse @dmarnel:

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

Pour Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)
2
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

L'animation sans reloadData () dans Swift peut être faite comme ceci (à partir de la version 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()

au cas où vous auriez besoin d'appeler reloadData () à la fin de l'animation, vous pouvez accepter les modifications apportées à CATransaction comme suit:

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

La logique est indiquée pour le cas lorsque vous supprimez des lignes, mais la même idée fonctionne également pour l'ajout de lignes. Vous pouvez également modifier l'animation en UITableViewRowAnimation.Left pour la rendre ordonnée ou choisir dans la liste des autres animations disponibles.

1
Vitalii

Si vous souhaitez ajouter vos propres animations personnalisées aux cellules UITableView, utilisez 

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

pour obtenir un tableau de cellules visibles. Ajoutez ensuite une animation personnalisée à chaque cellule.

Découvrez ce Gist que j'ai posté pour une animation de cellule personnalisée fluide . https://Gist.github.com/floprr/1b7a58e4a18449d962bd

1
flopr

Dans mon cas, je voulais ajouter 10 lignes supplémentaires dans la table (pour un type de fonctionnalité "afficher plus de résultats") et j'ai procédé comme suit:

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

Dans la plupart des cas, au lieu de "self.numberOfRows", vous utiliseriez généralement le nombre d'objets du tableau pour la vue de table. Pour que cette solution fonctionne bien pour vous, "arrayOfIndexPaths" doit donc être un tableau précis des chemins d'index des lignes insérées. Si la ligne existe pour l'un de ces chemins d'index, le code peut se bloquer, vous devez donc utiliser la méthode "reloadRowsAtIndexPaths: withRowAnimation:" pour ces chemins d'index afin d'éviter leur blocage

1
Lucas Chwe

Pour recharger toutes les sections , pas une seule avec durée personnalisée .

User duration paramètre de UIView.animate pour définir la durée personnalisée.

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