Quero reagir quando alguém sacode o iPhone. Eu particularmente não me importo com como eles agitam, apenas que foi acenado vigorosamente por uma fração de segundo. Alguém sabe como detectar isso?
fonte
Quero reagir quando alguém sacode o iPhone. Eu particularmente não me importo com como eles agitam, apenas que foi acenado vigorosamente por uma fração de segundo. Alguém sabe como detectar isso?
Na versão 3.0, agora existe uma maneira mais fácil de se conectar aos novos eventos de movimento.
O truque principal é que você precisa ter algum UIView (não o UIViewController) que deseja que o firstResponder receba as mensagens do evento shake. Aqui está o código que você pode usar em qualquer UIView para obter eventos de agitação:
@implementation ShakingView
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if ( event.subtype == UIEventSubtypeMotionShake )
{
// Put in code here to handle shake
}
if ( [super respondsToSelector:@selector(motionEnded:withEvent:)] )
[super motionEnded:motion withEvent:event];
}
- (BOOL)canBecomeFirstResponder
{ return YES; }
@end
Você pode transformar facilmente qualquer UIView (até mesmo visualizações do sistema) em uma visualização que possa obter o evento shake simplesmente subclassificando a visualização apenas com esses métodos (e selecionando esse novo tipo em vez do tipo base no IB, ou usando-o ao alocar um Visão).
No controlador de exibição, você deseja definir essa exibição para se tornar o primeiro respondedor:
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
Não se esqueça de que, se você tiver outras visualizações que se tornam a primeira resposta a partir de ações do usuário (como uma barra de pesquisa ou um campo de entrada de texto), também será necessário restaurar o status de resposta trémula da primeira exibição quando a outra exibição for renegada!
Este método funciona mesmo se você definir applicationSupportsShakeToEdit como NO.
viewDidAppear
vez deviewWillAppear
. Não sei por que; talvez a visualização precise estar visível antes de poder fazer o que for necessário para começar a receber os eventos de agitação?motionEnded
antes que o movimento realmente pare. Portanto, usando essa abordagem, você obtém uma série desconexa de batidas curtas, em vez de uma longa. A outra resposta funciona muito melhor neste caso.[super respondsToSelector:
não fará o que você deseja, pois é equivalente à chamada[self respondsToSelector:
que retornaráYES
. O que você precisa é[[ShakingView superclass] instancesRespondToSelector:
.Do meu aplicativo Diceshaker :
A histerese impede que o evento de agitação seja acionado várias vezes até que o usuário interrompa a agitação.
fonte
motionBegan
e osmotionEnded
eventos não são muito precisos ou precisos em termos de detecção do início e do fim exatos de um abalo. Essa abordagem permite que você seja tão preciso quanto desejar.Finalmente o fiz funcionar usando exemplos de código deste Tutorial do Gerenciador de Desfazer / Refazer .
É exatamente isso que você precisa fazer:
fonte
applicationSupportsShakeToEdit
éYES
.[self resignFirstResponder];
antes[super viewWillDisappear:animated];
? Isso parece peculiar.Primeiro, a resposta de 10 de julho de Kendall é direta.
Agora ... eu queria fazer algo semelhante (no iPhone OS 3.0+), mas no meu caso, eu queria que fosse em todo o aplicativo para que eu pudesse alertar várias partes do aplicativo quando um tremor ocorreu. Aqui está o que eu acabei fazendo.
Primeiro, subclassifiquei o UIWindow . Isso é fácil. Crie um novo arquivo de classe com uma interface como
MotionWindow : UIWindow
(fique à vontade para escolher o seu, natch). Adicione um método como este:Mude
@"DeviceShaken"
para o nome da notificação de sua escolha. Salve o arquivo.Agora, se você usar um MainWindow.xib (material de modelo Xcode padrão), vá lá e altere a classe do seu objeto Window de UIWindow para MotionWindow ou o que você chamou. Salve o xib. Se você configurar o UIWindow programaticamente, use sua nova classe Window lá.
Agora seu aplicativo está usando a classe UIWindow especializada . Onde você quiser saber sobre um shake, inscreva-se para receber as notificações! Como isso:
Para se remover como um observador:
Coloquei o meu em viewWillAppear: e viewWillDisappear: no que diz respeito aos controladores de exibição. Verifique se a sua resposta ao evento de agitação sabe se "já está em andamento" ou não. Caso contrário, se o dispositivo for sacudido duas vezes seguidas, você terá um congestionamento de trânsito lento. Dessa forma, você pode ignorar outras notificações até responder de verdade à notificação original.
Além disso: você pode optar por deixar o motionBegan vs. motionEnded . Você decide. No meu caso, o efeito sempre precisa ocorrer depois que o dispositivo está em repouso (vs. quando começa a tremer), então uso motionEnded . Experimente os dois e veja qual deles faz mais sentido ... ou detecte / notifique os dois!
Mais uma observação (curiosa?) Aqui: Observe que não há sinal de gerenciamento de socorristas neste código. Eu só tentei isso com os controladores de exibição de tabela até agora e tudo parece funcionar muito bem juntos! Mas não posso garantir outros cenários.
Kendall, et. al - alguém pode falar por que isso pode acontecer com as subclasses de UIWindow ? É porque a janela está no topo da cadeia alimentar?
fonte
Me deparei com este post procurando uma implementação "tremendo". A resposta de millenomi funcionou bem para mim, embora eu estivesse procurando por algo que exigisse um pouco mais de "ação trêmula" para disparar. Substituí o valor booleano por um int shakeCount. Também reimplementei o método L0AccelerationIsShaking () no Objective-C. Você pode ajustar a quantidade de agitação necessária ajustando a quantidade adicionada a shakeCount. Não tenho certeza de que encontrei os valores ideais ainda, mas parece estar funcionando bem até agora. Espero que isso ajude alguém:
PS: Eu configurei o intervalo de atualização para 1/15 de segundo.
fonte
Você precisa verificar o acelerômetro via accelerometer: didAccelerate: método que faz parte do protocolo UIAccelerometerDelegate e verificar se os valores ultrapassam um limite para a quantidade de movimento necessária para uma trepidação.
Há um código de amostra decente no acelerômetro: didAccelerate: método na parte inferior do AppController.m no exemplo GLPaint, disponível no site do desenvolvedor do iPhone.
fonte
No iOS 8.3 (talvez anterior) com Swift, é tão simples quanto substituir os métodos
motionBegan
oumotionEnded
no seu controlador de exibição:fonte
Este é o código delegado básico que você precisa:
Defina também o código apropriado na interface. ou seja:
@interface MyViewController: UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIAccelerometerDelegate>
fonte
Confira o exemplo do GLPaint.
http://developer.apple.com/library/ios/#samplecode/GLPaint/Introduction/Intro.html
fonte
Adicionar métodos a seguir no arquivo ViewController.m, funcionando corretamente
fonte
Desculpe postar isso como uma resposta, e não como um comentário, mas como você pode ver, eu sou novo no Stack Overflow e ainda não tenho reputação o suficiente para postar comentários!
De qualquer forma, eu digo à @cire sobre a garantia de definir o status de primeiro respondedor quando a exibição fizer parte da hierarquia da exibição. Portanto, definir o status de primeiro respondedor no
viewDidLoad
método de controladores de exibição não funcionará, por exemplo. E se você não tiver certeza se está funcionando,[view becomeFirstResponder]
retorna um booleano que você pode testar.Outro ponto: você pode usar um controlador de exibição para capturar o evento de agitação, se não desejar criar uma subclasse UIView desnecessariamente. Eu sei que não é tanto aborrecimento, mas ainda existe a opção. Basta mover os trechos de código que o Kendall colocou na subclasse UIView para o seu controlador e enviar as mensagens
becomeFirstResponder
eresignFirstResponder
para, emself
vez da subclasse UIView.fonte
Primeiro, sei que esse é um post antigo, mas ainda é relevante, e descobri que as duas respostas mais votadas não detectaram o tremor o mais cedo possível . É assim que se faz:
No seu ViewController:
fonte
A solução mais fácil é obter uma nova janela raiz para seu aplicativo:
Em seguida, no seu delegado do aplicativo:
Se você estiver usando um Storyboard, isso pode ser mais complicado, não sei exatamente o código que você precisará no delegado do aplicativo.
fonte
@implementation
desde Xcode 5.Basta usar esses três métodos para fazer isso
para detalhes, você pode verificar um código de exemplo completo por lá
fonte
Uma versão swiftease baseada na primeira resposta!
fonte
Para habilitar esse aplicativo, criei uma categoria no UIWindow:
fonte