Quiero reaccionar cuando alguien sacude el iPhone. No me importa particularmente cómo lo sacuden, solo que se agitó vigorosamente durante una fracción de segundo. ¿Alguien sabe cómo detectar esto?
fuente
Quiero reaccionar cuando alguien sacude el iPhone. No me importa particularmente cómo lo sacuden, solo que se agitó vigorosamente durante una fracción de segundo. ¿Alguien sabe cómo detectar esto?
En 3.0, ahora hay una manera más fácil: conectarse a los nuevos eventos de movimiento.
El truco principal es que necesita tener algo de UIView (no UIViewController) que desea como primer respondedor para recibir los mensajes de evento de sacudida. Aquí está el código que puede usar en cualquier UIView para obtener eventos de sacudida:
@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
Puede transformar fácilmente cualquier UIView (incluso vistas del sistema) en una vista que pueda obtener el evento shake simplemente subclasificando la vista solo con estos métodos (y luego seleccionando este nuevo tipo en lugar del tipo base en IB, o usándolo cuando se asigna un ver).
En el controlador de vista, desea configurar esta vista para convertirse en el primer respondedor:
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
¡No olvide que si tiene otras vistas que se convierten en el primer respondedor de las acciones del usuario (como una barra de búsqueda o un campo de entrada de texto) también necesitará restaurar el estado del primer respondedor de la vista temblorosa cuando la otra vista renuncie!
Este método funciona incluso si establece applicationSupportsShakeToEdit en NO.
viewDidAppear
lugar deviewWillAppear
. No estoy seguro de por qué; ¿Quizás la vista debe ser visible antes de poder hacer lo que sea para comenzar a recibir los eventos de sacudida?motionEnded
antes de que la sacudida se haya detenido. Entonces, usando este enfoque, obtienes una serie desarticulada de batidos cortos en lugar de uno largo. La otra respuesta funciona mucho mejor en este caso.[super respondsToSelector:
no hará lo que quieras, ya que es equivalente a llamar[self respondsToSelector:
y volveráYES
. Lo que necesita es[[ShakingView superclass] instancesRespondToSelector:
.Desde mi aplicación Diceshaker :
La histéresis evita que el evento de sacudida se active varias veces hasta que el usuario detiene la sacudida.
fuente
motionBegan
y losmotionEnded
eventos no son muy precisos o precisos en términos de detectar el inicio y el final exactos de un batido. Este enfoque le permite ser tan preciso como desee.Finalmente lo hice funcionar usando ejemplos de código de este Tutorial del Administrador de Deshacer / Rehacer .
Esto es exactamente lo que debes hacer:
fuente
applicationSupportsShakeToEdit
esYES
.[self resignFirstResponder];
antes[super viewWillDisappear:animated];
? Esto parece peculiar.Primero, la respuesta del 10 de julio de Kendall es acertada.
Ahora ... quería hacer algo similar (en iPhone OS 3.0+), solo en mi caso lo quería en toda la aplicación para poder alertar a varias partes de la aplicación cuando ocurriera una sacudida. Esto es lo que terminé haciendo.
Primero, subclasifiqué UIWindow . Esto es fácil, fácil. Cree un nuevo archivo de clase con una interfaz como
MotionWindow : UIWindow
(siéntase libre de elegir el suyo, natch). Agregue un método como este:Cambie
@"DeviceShaken"
al nombre de notificación de su elección. Guarda el archivo.Ahora, si usa un MainWindow.xib (material de plantilla Xcode de stock), entre allí y cambie la clase de su objeto Window de UIWindow a MotionWindow o como lo llame. Guarda el xib. Si configura UIWindow mediante programación, use su nueva clase Window allí.
Ahora su aplicación está utilizando la clase especializada UIWindow . Donde quiera que te informen sobre un batido, ¡regístrate para recibir notificaciones! Me gusta esto:
Para eliminarse como observador:
Puse el mío en viewWillAppear: y viewWillDisappear: en lo que respecta a los controladores de vista. Asegúrese de que su respuesta al evento shake sepa si está "en progreso" o no. De lo contrario, si el dispositivo se agita dos veces seguidas, tendrá un pequeño atasco de tráfico. De esta manera, puede ignorar otras notificaciones hasta que haya terminado de responder a la notificación original.
Además: puede elegir salir de motionBegan vs. motionEnded . Tu decides. En mi caso, el efecto siempre debe tener lugar después de que el dispositivo esté en reposo (frente a cuando comienza a temblar), por lo que utilizo motionEnded . Pruebe ambos y vea cuál tiene más sentido ... ¡o detecte / notifique a ambos!
Una observación más (¿curiosa?) Aquí: observe que no hay signos de administración de primeros respondedores en este código. ¡Hasta ahora solo he probado esto con Table View Controllers y todo parece funcionar muy bien juntos! Sin embargo, no puedo responder por otros escenarios.
Kendall, et. ¿Alguien puede hablar de por qué esto podría ser así para las subclases de UIWindow ? ¿Es porque la ventana está en la parte superior de la cadena alimentaria?
fuente
Encontré esta publicación buscando una implementación "temblorosa". La respuesta de millenomi funcionó bien para mí, aunque estaba buscando algo que requiriera un poco más de "acción de sacudida" para desencadenarse. He reemplazado el valor booleano con un int shakeCount. También reimplementé el método L0AccelerationIsShaking () en Objective-C. Puede ajustar la cantidad de temblor requerida ajustando la cantidad agregada a shakeCount. No estoy seguro de haber encontrado los valores óptimos todavía, pero parece estar funcionando bien hasta ahora. Espero que esto ayude a alguien:
PD: he configurado el intervalo de actualización a 1/15 de segundo.
fuente
Debe verificar el acelerómetro a través del acelerómetro: didAccelerate: método que forma parte del protocolo UIAccelerometerDelegate y verificar si los valores superan un umbral para la cantidad de movimiento necesaria para una sacudida.
Hay un código de muestra decente en el acelerómetro: didAccelerate: método justo en la parte inferior de AppController.m en el ejemplo de GLPaint que está disponible en el sitio para desarrolladores de iPhone.
fuente
En iOS 8.3 (quizás antes) con Swift, es tan simple como anular los métodos
motionBegan
omotionEnded
en su controlador de vista:fuente
Este es el código de delegado básico que necesita:
Establezca también en el código apropiado en la interfaz. es decir:
@interface MyViewController: UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIAccelerometerDelegate>
fuente
Mira el ejemplo de GLPaint.
http://developer.apple.com/library/ios/#samplecode/GLPaint/Introduction/Intro.html
fuente
Agregue los siguientes métodos en el archivo ViewController.m, funciona correctamente
fuente
Lamento publicar esto como una respuesta en lugar de un comentario, pero como puede ver, soy nuevo en Stack Overflow y, por lo tanto, todavía no tengo la reputación suficiente para publicar comentarios.
De todos modos, secundo a @cire para asegurarme de establecer el primer estado de respuesta una vez que la vista es parte de la jerarquía de vistas. Por lo tanto, establecer el estado del primer respondedor en su
viewDidLoad
método de controladores de vista no funcionará, por ejemplo. Y si no está seguro de si está funcionando, le[view becomeFirstResponder]
devuelve un valor booleano que puede probar.Otro punto: puede usar un controlador de vista para capturar el evento de sacudida si no desea crear una subclase UIView innecesariamente. Sé que no es tanta molestia, pero aún así la opción está ahí. Simplemente mueva los fragmentos de código que Kendall puso en la subclase UIView a su controlador y envíe los mensajes
becomeFirstResponder
yresignFirstResponder
a enself
lugar de la subclase UIView.fuente
En primer lugar, sé que esta es una publicación antigua, pero aún es relevante, y descubrí que las dos respuestas mejor votadas no detectaron la sacudida lo antes posible . Asi es como se hace:
En su ViewController:
fuente
La solución más fácil es derivar una nueva ventana raíz para su aplicación:
Luego, en su aplicación delegado:
Si está utilizando un Storyboard, esto puede ser más complicado, no sé con precisión el código que necesitará en el delegado de la aplicación.
fuente
@implementation
puesto Xcode 5.Solo usa estos tres métodos para hacerlo
para más detalles, puede consultar un código de ejemplo completo allí
fuente
¡Una versión rápida basada en la primera respuesta!
fuente
Para habilitar esta aplicación, creé una categoría en UIWindow:
fuente