web-dev-qa-db-fra.com

UIRefreshControl endRefreshing n'est pas lisse

Lorsque mes données ont fini de se charger et que mon tableau a été rechargé, j'appelle endRefreshing sur mon contrôle d'actualisation, il «saute» alors de son état de chargement et disparaît. Comment puis-je implémenter une animation fluide qui éloigne le contrôle d'actualisation lorsqu'il est terminé ?

17
Halpo

J'ajoute une nouvelle réponse puisque la seule qui ne soit pas très précise dans l'explication. Et ce serait probablement trop pour les commentaires.

La solution de Halpo est correcte. Mais la raison mentionnée est fausse.

L'appel de -[NSObject (NSDelayedPerforming) performSelector:withObject:afterDelay:] garantit que l'appel sera effectué lors de la prochaine itération du cycle d'exécution.

Donc, cela ne fonctionne pas, car il y a un petit délai, mais vous le déplacez vers la boucle suivante.

En fait, vous devriez/pourriez réduire le délai à 0.0 et cela fonctionnerait toujours. En outre, une implémentation plus correcte (en termes d'utilisation de l'objet destiné à obtenir quelque chose, pas de meilleur résultat) est possible.

Voici les différents extraits de code pour cela:

// SOLUTION I

[[self tableView] reloadData];
[[self refreshControl] performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.0];

// SOLUTION II (semantically correct)

[[self tableView] reloadData];
[[NSOperationQueue currentQueue] addOperationWithBlock:^{
    [[self refreshControl] endRefreshing];
}];

// SOLUTION III (GCD)

dispatch_async(dispatch_get_main_queue(), ^{
    [[self refreshControl] endRefreshing];
}];

EDIT

Comme l'a souligné johann-fradj , vous pouvez également utiliser GCD. J'aime beaucoup GCD, mais je pense que la solution II décrit le mieux ce qui se passe. De plus, GCD n’est pas très objectif, donc je préfère personnellement me contenter de ma solution.

23
Julian F. Weinert

Correction du problème - j'ai ajouté un petit délai pour endRefresh après le rechargement des données:

[self.tableView reloadData];
[self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.05];
24
Halpo

Solution rapide 4

    tableView.reloadData()
    if refreshControl?.isRefreshing == true {
        DispatchQueue.main.async {
            self.refreshControl?.endRefreshing()
        }
    }

D'autres solutions (délai, utilisation de CATransaction, ...) sont plus complexes et ne donnent aucun avantage visible 

3
coldfire

Essayez d'encapsuler l'appel à endRefreshing() dans un bloc d'animation UIView:

J'ai aussi rencontré ce problème. Pour endRefreshing() La documentation indique:

UIView.animateWithDuration(0.5) {
    self.refreshControl.endRefreshing()
}

La documentation indique: 

Si les animations sont également activées, le contrôle est masqué à l'aide d'une animation.

1
Eytan

Une des raisons peut être que vous actualisez votre vue table après l'appel de endRefresh. Par exemple, mes appels ressemblaient à ceci:

[self.refreshControl beginRefreshing];
[self.network getThings:^(id things, NSError *error) {
    [self.refreshControl endRefreshing];

    if (error) {
        ...
    } else {
        self.things = things;
        [self.tableView reloadData];
    }
}];

Ce qui est mauvais, car la table se met à jour pendant l'exécution de l'animation endRefresh. Donc, le code bien fait ressemble à ceci:

[self.refreshControl beginRefreshing];
[self.network getThings:^(id things, NSError *error) {
    if (error) {
        [self.refreshControl endRefreshing];
        ...
    } else {
        self.things = things;
        [self.tableView reloadData];
        [self.refreshControl endRefreshing];
    }
}];
0
gklka