IOS: ActivityIndicator sur UITableView … Comment?

Je veux afficher un indicateur d'activité sur un uitableview pendant le chargement des données (dans un autre thread). Donc, dans la méthode ViewDidLoad de UITableViewController:

-(void)viewDidLoad { [super viewDidLoad]; //I create the activity indicator UIActivityIndicatorView *ac = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; [ac startAnimating]; //Create the queue to download data from internet dispatch_queue_t downloadQueue = dispatch_queue_create("PhotoDownload",NULL); dispatch_async(downloadQueue, ^{ //Download photo ....... ....... dispatch_async(dispatch_get_main_queue(), ^{ ...... ...... [ac stopAnimating]; }); }); ....... 

Pourquoi l'indicateur d'activité ne s'affiche pas sur la vue de la table? Comment puis-je y arriver?

Vous devez append le UIActivityIndicatorView à quelque chose. Vous pouvez l'append à une vue d'en-tête UITableView. Pour ce faire, vous devrez fournir votre propre vue personnalisée.

 ... UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)]; [view addSubview:ac]; // <-- Your UIActivityIndicatorView self.tableView.tableHeaderView = view; ... 

J'ai essayé de find une solution pour cela et j'ai lu beaucoup de forums, mais je n'ai pas eu ce que je voulais. Après avoir compris comment fonctionne l'indicateur d'activité et le controller de vue de table, j'ai trouvé la solution suivante.

Pour une raison quelconque, si vous essayez de démarrer l'indicateur d'activité sur le même thread avec le paramètre tableReload ou tout autre process coûteux, l'indicateur d'activité ne s'exécute jamais. Si vous essayez d'exécuter le rechargement de la table ou une autre opération dans un autre thread, il se peut que cela ne soit pas sûr et puisse produire des erreurs ou des résultats indésirables. Nous pouvons donc exécuter la méthode qui présente l'indicateur d'activité sur un autre thread.

J'ai également combiné cette solution avec le MBProgressHUD pour présenter quelque chose de plus joli qu'une vue avec un indicateur d'activité. Dans tous les cas, l'apparence de l'activité peut être personnalisée.

 -(void)showActivityViewer { AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; UIWindow *window = delegate.window; activityView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, window.bounds.size.width, window.bounds.size.height)]; activityView.backgroundColor = [UIColor blackColor]; activityView.alpha = 0.5; UIActivityIndicatorView *activityWheel = [[UIActivityIndicatorView alloc] initWithFrame: CGRectMake(window.bounds.size.width / 2 - 12, window.bounds.size.height / 2 - 12, 24, 24)]; activityWheel.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite; activityWheel.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); [activityView addSubview:activityWheel]; [window addSubview: activityView]; [[[activityView subviews] objectAtIndex:0] startAnimating]; } -(void)hideActivityViewer { [[[activityView subviews] objectAtIndex:0] stopAnimating]; [activityView removeFromSuperview]; activityView = nil; } - (IBAction)reloadDataAction:(id)sender { [NSThread detachNewThreadSelector:@selector(showActivityViewer) toTarget:self withObject:nil]; //... do your reload or expensive operations [self hideActivityViewer]; } 

[iOS 5 +]
Si vous souhaitez simplement afficher activityWheel sans une vue parent supplémentaire, vous pouvez également append activityWheel directement à tableView et calculer la valeur y pour le cadre en utilisant le tableau de bord contentOffset:

 @interface MyTableViewController () @property (nonatomic, strong) UIActivityIndicatorView *activityView; @end // .... - (void) showActivityView { if (self.activityView==nil) { self.activityView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero]; [self.tableView addSubview:self.activityView]; self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; self.activityView.hidesWhenStopped = YES; // additional setup... // self.activityView.color = [UIColor redColor]; } // Center CGFloat x = UIScreen.mainScreen.applicationFrame.size.width/2; CGFloat y = UIScreen.mainScreen.applicationFrame.size.height/2; // Offset. If tableView has been scrolled CGFloat yOffset = self.tableView.contentOffset.y; self.activityView.frame = CGRectMake(x, y + yOffset, 0, 0); self.activityView.hidden = NO; [self.activityView startAnimating]; } - (void) hideActivityView { [self.activityView stopAnimating]; } 

Si ActivityView n'apparaît pas immédiatement (ou jamais), reportez-vous à la réponse de zirinisp ou effectuez le gros travail en arrière-plan.

Il y a une solution de contournement pour UIViewController. (Vous pouvez utiliser un UIViewController avec une vue de table pour get un UITableViewController.) Dans le storyboard, ajoutez un indicateur activityIndicator dans la vue de UIViewController. Ensuite, dans viewDidLoad, ajoutez les éléments suivants:

 [self.activityIndicator layer].zPosition = 1; 

L'indicateur d'activité sera affiché sur la vue de la table.

Bien que la question soit plutôt ancienne, j'ajoute la mienne aussi. [IOS 8+] Ce qui précède ne fonctionne pas pour moi. Au lieu de cela, je stocke la vue de l'indicateur (ac) dans la class. Alors je fais:

 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (ac.isAnimating) return 50.0f; return 0.0f; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if (ac.isAnimating) return ac; return nil; } 

Pour montrer l'indicateur, je fais

 [ac startAnimating] 

Pour le cacher, je fais

 [ac stopAnimating] 

J'espère que cela aide quelqu'un.