ios - recuperar - ver notificaciones antiguas iphone
¿Cómo detecto cuando alguien sacude un iPhone? (16)
Agregue los siguientes métodos en el archivo ViewController.m, funciona correctamente
-(BOOL) canBecomeFirstResponder
{
/* Here, We want our view (not viewcontroller) as first responder
to receive shake event message */
return YES;
}
-(void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if(event.subtype==UIEventSubtypeMotionShake)
{
// Code at shake event
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"Motion" message:@"Phone Vibrate"delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];
[self.view setBackgroundColor:[UIColor redColor]];
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self becomeFirstResponder]; // View as first responder
}
Quiero reaccionar cuando alguien sacude el iPhone. No me importa especialmente cómo lo sacuden, solo que se agitó vigorosamente por una fracción de segundo. ¿Alguien sabe como detectar esto?
Debe verificar el acelerómetro a través del acelerómetro: método Acelerado: que forma parte del protocolo UIAccelerometerDelegate y verificar si los valores superan el umbral para la cantidad de movimiento necesario para un movimiento.
Hay un código de muestra decente en el acelerómetro: didAccelerate: method justo en la parte inferior de AppController.m en el ejemplo de GLPaint que está disponible en el sitio de desarrolladores de iPhone.
Desde mi aplicación Diceshaker :
// Ensures the shake is strong enough on at least two axes before declaring it a shake.
// "Strong enough" means "greater than a client-supplied threshold" in G''s.
static BOOL L0AccelerationIsShaking(UIAcceleration* last, UIAcceleration* current, double threshold) {
double
deltaX = fabs(last.x - current.x),
deltaY = fabs(last.y - current.y),
deltaZ = fabs(last.z - current.z);
return
(deltaX > threshold && deltaY > threshold) ||
(deltaX > threshold && deltaZ > threshold) ||
(deltaY > threshold && deltaZ > threshold);
}
@interface L0AppDelegate : NSObject <UIApplicationDelegate> {
BOOL histeresisExcited;
UIAcceleration* lastAcceleration;
}
@property(retain) UIAcceleration* lastAcceleration;
@end
@implementation L0AppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[UIAccelerometer sharedAccelerometer].delegate = self;
}
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (self.lastAcceleration) {
if (!histeresisExcited && L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.7)) {
histeresisExcited = YES;
/* SHAKE DETECTED. DO HERE WHAT YOU WANT. */
} else if (histeresisExcited && !L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.2)) {
histeresisExcited = NO;
}
}
self.lastAcceleration = acceleration;
}
// and proper @synthesize and -dealloc boilerplate code
@end
La histéresis evita que el evento de sacudida se dispare varias veces hasta que el usuario detiene la sacudida.
En iOS 8.3 (quizás antes) con Swift, es tan simple como reemplazar los métodos motionBegan
o motionEnded
en tu controlador de vista:
class ViewController: UIViewController {
override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent) {
println("started shaking!")
}
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent) {
println("ended shaking!")
}
}
En la versión 3.0, ahora hay una forma más fácil: enganche en los nuevos eventos de movimiento.
El truco principal es que necesitas tener un UIView (no UIViewController) que desees como firstResponder para recibir los mensajes del evento Shake Aquí está el código que puede usar en cualquier UIView para obtener eventos de shake:
@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 al asignar 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 vibrante cuando la otra vista renuncie!
Este método funciona incluso si establece applicationSupportsShakeToEdit en NO.
En primer lugar, sé que este es un post antiguo, pero sigue siendo relevante, y encontré que las dos respuestas más votadas no detectaron el temblor lo antes posible . Asi es como se hace:
- Enlace CoreMotion a su proyecto en las fases de construcción del objetivo:
En su ViewController:
- (BOOL)canBecomeFirstResponder { return YES; } - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { if (motion == UIEventSubtypeMotionShake) { // Shake detected. } }
Este es el código de delegado básico que necesitas:
#define kAccelerationThreshold 2.2
#pragma mark -
#pragma mark UIAccelerometerDelegate Methods
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if (fabsf(acceleration.x) > kAccelerationThreshold || fabsf(acceleration.y) > kAccelerationThreshold || fabsf(acceleration.z) > kAccelerationThreshold)
[self myShakeMethodGoesHere];
}
También establece el en el código apropiado en la interfaz. es decir:
@interface MyViewController: UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UIAccelerometerDelegate>
Finalmente lo hice funcionar usando ejemplos de código de este tutorial de deshacer / rehacer administrador .
Esto es exactamente lo que necesitas hacer:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
application.applicationSupportsShakeToEdit = YES;
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
-(BOOL)canBecomeFirstResponder {
return YES;
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[self resignFirstResponder];
[super viewWillDisappear:animated];
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake)
{
// your code
}
}
La solución más sencilla es derivar una nueva ventana raíz para su aplicación:
@implementation OMGWindow : UIWindow
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventTypeMotion && motion == UIEventSubtypeMotionShake) {
// via notification or something
}
}
@end
Luego en su solicitud delegado:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[OMGWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
//…
}
Si está utilizando un Guión gráfico, esto puede ser más complicado, no sé exactamente el código que necesitará en el delegado de la aplicación.
Lamento publicar esto como una respuesta en lugar de un comentario, pero como puede ver, soy nuevo en y, por lo tanto, ¡aún no tengo la reputación suficiente para publicar comentarios!
De todos modos, segundo @Cire sobre asegurarse de establecer el primer estado de respuesta una vez que la vista forme parte de la jerarquía de vistas. Por lo tanto, establecer el estado del primer respondedor en sus controladores de vista, el método viewDidLoad
no funcionará, por ejemplo. Y si no está seguro de si está funcionando, [view becomeFirstResponder]
devuelve un booleano que puede probar.
Otro punto: puede usar un controlador de vista para capturar el evento shake si no desea crear una subclase UIView innecesariamente. Sé que no es mucha molestia pero todavía existe la opción. Simplemente mueva los fragmentos de código que Kendall puso en la subclase UIView a su controlador y envíe los mensajes becomeFirstResponder
y resignFirstResponder
a self
lugar de la subclase UIView.
Me encontré con este post buscando una implementación "temblando". La respuesta de Millenomi funcionó bien para mí, aunque estaba buscando algo que requería un poco más de "acción de sacudida" para activarse. He reemplazado a valor booleano con un int shakeCount. También reimplementé el método L0AccelerationIsShaking () en Objective-C. Puede modificar la cantidad de agitación 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:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
if (self.lastAcceleration) {
if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7] && shakeCount >= 9) {
//Shaking here, DO stuff.
shakeCount = 0;
} else if ([self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.7]) {
shakeCount = shakeCount + 5;
}else if (![self AccelerationIsShakingLast:self.lastAcceleration current:acceleration threshold:0.2]) {
if (shakeCount > 0) {
shakeCount--;
}
}
}
self.lastAcceleration = acceleration;
}
- (BOOL) AccelerationIsShakingLast:(UIAcceleration *)last current:(UIAcceleration *)current threshold:(double)threshold {
double
deltaX = fabs(last.x - current.x),
deltaY = fabs(last.y - current.y),
deltaZ = fabs(last.z - current.z);
return
(deltaX > threshold && deltaY > threshold) ||
(deltaX > threshold && deltaZ > threshold) ||
(deltaY > threshold && deltaZ > threshold);
}
PS: He establecido el intervalo de actualización en 1/15 de segundo.
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 15)];
Mira el ejemplo de GLPaint.
http://developer.apple.com/library/ios/#samplecode/GLPaint/Introduction/Intro.html
Para habilitar esta aplicación en toda la aplicación, creé una categoría en UIWindow:
@implementation UIWindow (Utils)
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake) {
// Do whatever you want here...
}
}
@end
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 ocurría una sacudida. Esto es lo que terminé haciendo.
En primer lugar, he subclasificado UIWindow . Esto es fácil peasy. Crea un nuevo archivo de clase con una interfaz como MotionWindow : UIWindow
(siéntete libre de elegir el tuyo, natch). Agrega un método así:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"DeviceShaken" object:self];
}
}
Cambie @"DeviceShaken"
al nombre de notificación de su elección. Guarda el archivo.
Ahora, si usa un MainWindow.xib (plantilla de plantilla Xcode de valores), vaya allí y cambie la clase de su objeto Window de UIWindow a MotionWindow o como quiera que lo llame. Guarde el xib. Si configura UIWindow mediante programación, use su nueva clase de Windows allí.
Ahora su aplicación está utilizando la clase especializada UIWindow . ¡Donde quiera que se le informe sobre un batido, inscríbase para recibir notificaciones! Me gusta esto:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deviceShaken) name:@"DeviceShaken" object:nil];
Para quitarte a ti mismo como un observador:
[[NSNotificationCenter defaultCenter] removeObserver:self];
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, se producirá un pequeño atasco de tráfico. De esta manera, puede ignorar otras notificaciones hasta que realmente haya terminado de responder a la notificación original.
También: puedes elegir salir de motionBegan contra motionEnded . Tu decides. En mi caso, el efecto siempre debe tener lugar después de que el dispositivo está en reposo (en comparación con cuando comienza a temblar), por lo que uso motionEnded . Pruebe ambos y vea cuál tiene más sentido ... ¡o detecte / notifique para ambos!
Una observación más (¿curiosa?) Aquí: note que no hay signos de administración de primeros respondedores en este código. ¡Solo he intentado esto con los controladores de vista de tabla hasta ahora y todo parece funcionar bastante bien juntos! Sin embargo, no puedo responder por otros escenarios.
Kendall, et. al - ¿Alguien puede hablar sobre 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?
Solo usa estos tres métodos para hacerlo
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event{
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event{
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{
para detalles puedes revisar un código de ejemplo completo there
Una versión rápida basada en la primera respuesta!
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
if ( event?.subtype == .motionShake )
{
print("stop shaking me!")
}
}