Pergunta

Eu tenho um uabableViewController, que é rootViewController. É XIB apenas uma visualização de tabela. Adicionei um uiacityIndicator através do IB e criei um iboutlet. Adicionei programaticamente uma barra de ferramentas com um botão de exclusão ao rootViewController. Quando o usuário clica no botão Excluir da barra de ferramentas, quero exibir o indicador, centrado na tela. O método abaixo exclui dados de um banco de dados, que acontece muito rápido. Eu quero que o usuário saiba que algo está acontecendo. Se eu executar o código abaixo sem sono (), ele acontece rapidamente e não vejo o indicador. Mas alguns por algum motivo, não estou vendo o indicador de qualquer maneira. Estou supondo que o sono () bloqueie a repintura? Se eu tomar sono () e as duas últimas linhas, vejo o indicador, mas é claro que ele nunca desaparece. Ele também é exibido no canto superior esquerdo da janela.

Como faço para que o código abaixo funcione para que o indicador seja exibido por 1/2 a 1 segundo, pelo menos?

Como alinha o indicador no meio da janela?

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

//do something which might happen really fast

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

Solução

O spinner não começará a girar até que você processe o evento e retorne ao loop de corrida. A maneira de contornar isso é pedir ao loop de corrida para terminar as coisas para você.

Aqui está um exemplo do que quero dizer:

- (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: Não há nada neste código que garantisse que ele o processe outros toques durante o período de "sono", portanto, bloqueie outros eventos de alguma forma.

Outras dicas

Como Adam mencionou, o spinner não será exibido, a menos que o trabalho (neste caso a operação de exclusão) seja feita em um encadeamento de segundo plano. Este é o código que comecei a trabalhar com base no código inicial de Brent. Modifiquei para chamar minha função que faz o trabalho em um encadeamento de segundo plano e, em seguida, use o encadeamento principal para remover o spinner quando pronto.

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

O problema é que, enquanto você faz o que você gosta, o loop de corrida principal não está em execução. Para que o indicador de atividade seja exibido, o loop de corrida principal precisa estar em execução para que possa atualizar sua animação. Para obter o comportamento pretendido, você precisará fazer sua operação de banco de dados de forma assíncrona em um encadeamento separado.

self.navigationController.View AddSubView: ActivityIndicator]; [ActivityIndicator Startanimating];

Auto -executivo: @selector (removepinner :) withObject: ActivityIndicator AfterDelay: 5.0];

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top