2012-04-28 17 views
18

Quiero mostrar un indicador de actividad sobre un uitableview mientras está cargando datos (en otro hilo). Así que en el método de la viewDidLoad UITableViewController:IOS: ActivityIndicator sobre UITableView ... ¿Cómo?

-(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]; 
     }); 
    }); 
    ....... 

Por qué el indicador de actividad no se muestran durante la vista de tabla? ¿Cómo puedo lograrlo?

+0

También interesado en esta pregunta.Pero hasta donde sé, las subclases de UIView no son seguras para subprocesos. –

Respuesta

21

Debe agregar UIActivityIndicatorView a algo. Puede agregarlo a una vista de encabezado UITableView. Para hacer esto, deberá proporcionar su propia vista personalizada.

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

¡Sume al golpe! +1 por la respuesta. Un indicador de actividad es un UIView, por lo que debe agregarse a la jerarquía de vistas de alguna manera. – jmstone617

+0

y dónde vive ac antes de agregarlo a la vista recién creada? – sports

12

que han estado tratando de encontrar una solución para eso y han leído un montón de foros, pero no he tenido lo que quería. Después de entender cómo funciona el indicador de actividad y el controlador de vista de tabla, se me ocurrió la siguiente solución.

Por alguna razón, si intenta iniciar el indicador de actividad en el mismo subproceso con la carga de tabla o cualquier otro proceso costoso, el indicador de actividad nunca se ejecuta. Si intenta ejecutar la carga de tabla o alguna otra operación en otro subproceso, entonces podría no ser seguro y podría producir errores o resultados no deseados. Entonces podemos ejecutar el método que presenta el indicador de actividad en otro hilo.

También he combinado esta solución con MBProgressHUD para presentar algo que se vea mejor que una vista con un indicador de actividad. En cualquier caso, las miradas de activityView se pueden personalizar.

-(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]; 
} 
+0

Esto funcionó bastante bien para mí, después de varias alternativas. Gracias @zirinisp! – dfdumaresq

+0

estado buscando desde hace bastante tiempo y tengo que decir que esta es la mejor solución hasta ahora. – cookiemonsta

+0

Esto funciona, pero ¿cómo puedo mover esto a una clase auxiliar para que pueda llamar a cualquier vista? – aherrick

6

[iOS 5 +]
Si lo que desea es mostrar la activityWheel sin un parentview adicional, también se puede añadir el activityWheel directamente a la tableView y calcular el valor de y para el marco mediante el tableViews 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 el activityView no aparece inmediatamente (o nunca), se refieren a la respuesta de zirinisp o hacer el trabajo pesado en el fondo.

4

Hay una solución para UIViewController. (Puede usar un UIViewController con una vista de tabla para lograr un UITableViewController). En el guión gráfico, agregue un indicador de actividad en la vista de UIViewController. Luego, en viewDidLoad, añadir lo siguiente:

[self.activityIndicator layer].zPosition = 1; 

El activityIndicator se mostrará durante la vista de tabla.

-1

Aunque la pregunta es bastante antigua, agrego la mía también. [IOS 8+] Lo anterior no funciona para mí. En cambio, guardo la vista del indicador (ac) en la clase. entonces yo:

- (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; 
} 

Para que muestra la indicatorview hago

[ac startAnimating] 

Para ocultarlo, lo hago

[ac stopAnimating] 

Espero que esto sea de ayuda a alguien.

Cuestiones relacionadas