Pregunta

Tengo un UITableViewController, que es RootViewController. Es XIB solo tiene una vista de tabla. He agregado un UIActivityIndicator a través de IB y he creado un IBOutlet. He agregado mediante programación una barra de herramientas con un botón de eliminación al RootViewController. Cuando el usuario haga clic en el botón de eliminar de la barra de herramientas, quiero mostrar el indicador, centrado en la pantalla. El siguiente método elimina los datos de una base de datos, lo que sucede muy rápido. Quiero que el usuario sepa que algo está sucediendo. Si ejecuto el código de abajo sin dormir (), sucede que es rápido y no veo el indicador. Pero algunos por alguna razón, no estoy viendo el indicador de todos modos. Estoy adivinando dormir () bloques de repintado? Si saco sleep () y las dos últimas líneas, veo el indicador pero, por supuesto, nunca desaparece. También se muestra en la parte superior izquierda de la ventana.

¿Cómo consigo que el código de abajo funcione para que el indicador se muestre por lo menos durante 1/2 - 1 segundo?

¿Cómo puedo alinear el indicador en el centro de la ventana?

[self.navigationController.view addSubview:activityIndicator];
[activityIndicator startAnimating];
[activityIndicator setNeedsDisplay];

//do something which might happen really fast

sleep(1); //create illusion
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
¿Fue útil?

Solución

La ruleta no comenzará a girar hasta que haya procesado el evento y haya regresado al bucle de ejecución. La forma de evitar esto es pedirle al bucle de ejecución que termine las cosas por usted.

Aquí hay un ejemplo de lo que quiero decir:

- (IBAction)deleteAction:(id)sender {
    [self.navigationController.view addSubview:activityIndicator];
    [activityIndicator startAnimating];

    // Spinner won't start spinning until we finish processing this event, so
    // we're just going to schedule the rest of what we need to do.

    // doDelete: will run when the main thread gets its next event.
    [self performSelectorOnMainThread:@selector(doDelete:)
                           withObject:record
                        waitUntilDone:NO];

    // removeSpinner: will run in at least one second, but will wait if
    // another event (like the doDelete: one) is in the middle of running.
    [self performSelector:@selector(removeSpinner:)
               withObject:activityIndicator
               afterDelay:1.0];
}
- (void)doDelete:(id)record {
    [record delete];   // or whatever it is you need to do
}
- (void)removeSpinner:(UIActivityIndicator*)activityIndicator {
    [activityIndicator stopAnimating];
    [activityIndicator removeFromSuperview];
}

Nota: no hay nada en este código que garantice que deje de procesar otros toques durante el " sueño " período, así que asegúrate de bloquear otros eventos de alguna manera.

Otros consejos

Como mencionó Adam, el control de giro no se mostrará a menos que el trabajo (en este caso la operación de eliminación) se realice en un subproceso en segundo plano. Este es el código que tengo que trabajar basado en el código inicial de Brent. Lo modifiqué para llamar a mi función que realiza el trabajo en un subproceso en segundo plano, y luego usar el subproceso principal para quitar la rueda giratoria cuando haya terminado.

- (void)removeSpinner:(id)record {
    [activityIndicator stopAnimating];
    [activityIndicator removeFromSuperview];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Thank You" message:@"Thanks for your feedback!"
                                                                                                 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
    [alert release];

    // return to feedings tab
  tabBarController.selectedIndex = 0;
}


- (void)doFeedback:(id)record {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int j;
    for (int i = 0; i < 1000000000; i++) {
        j = j + i;
    }
    [self performSelectorOnMainThread:@selector(removeSpinner:) withObject:nil waitUntilDone:NO];

    [pool release];
}


- (IBAction)handleSend {        
    [self.view addSubview:activityIndicator];
    [activityIndicator startAnimating];

    // Spinner won't start spinning until we finish processing this event, so
    // we're just going to schedule the rest of what we need to do. 
    // doFeedback: will run when the main thread gets its next event.   
    [self performSelectorInBackground:@selector(doFeedback:) withObject:nil];
}

El problema es que, mientras estás haciendo lo tuyo, el ciclo de ejecución principal no se está ejecutando. Para que se muestre el indicador de actividad, el ciclo de ejecución principal debe estar ejecutándose para poder actualizar su animación. Para obtener el comportamiento deseado, deberá realizar la operación de la base de datos de forma asíncrona en un subproceso independiente.

[self.navigationController.view addSubview: activityIndicator]; [activityIndicator startAnimating];

[self performSelector: @selector (removeSpinner :)                withObject: activityIndicator                afterDelay: 5.0];

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top