Cómo detectar toques en la barra de estado

Tengo una vista personalizada en mi aplicación que puede ser desplazada por el usuario. Esta vista, sin embargo, no henetworkinga de UIScrollView. Ahora quiero que el usuario pueda desplazar esta vista hacia la parte superior, tal como lo permite cualquier otra vista desplazable. Pensé que no hay forma directa de hacerlo.

Google presentó una solución: http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html Esto ya no funciona en iOS 4.x. Eso es un no ir.

Tuve la idea de crear una vista de desplazamiento y mantenerla en algún lugar, solo para ver sus notifications y luego reenviarlas a mi control. Esta no es una buena forma de resolver mi problema, así que estoy buscando soluciones "más limpias". Me gusta el enfoque general del enlace antes mencionado para subclass UIApplication. ¿Pero qué API puede darme información confiable?

¿Hay algún pensamiento, ayuda, etc.?

Editar: Otra cosa que no me gusta de mi solución actual es que solo funciona siempre y cuando la vista actual no tenga ninguna vista de desplazamiento. El gesto de desplazamiento hacia arriba funciona solo si hay exactamente una vista de desplazamiento alnetworkingedor. Tan pronto como se agregue el muñeco (vea mi respuesta a continuación para más detalles) a una vista con otra vista de desplazamiento, el gesto está completamente deshabilitado. Otra razón para search una solución mejor …

Finalmente, he reunido la solución de trabajo de las respuestas aquí. Gracias muchachos

Declare el nombre de la notificación en algún lugar (por ejemplo, AppDelegate.h):

static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification"; 

Agregue las siguientes líneas a su AppDelegate.m:

 #pragma mark - Status bar touch tracking - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]]; CGRect statusBarFrame = [UIApplication shanetworkingApplication].statusBarFrame; if (CGRectContainsPoint(statusBarFrame, location)) { [self statusBarTouchedAction]; } } - (void)statusBarTouchedAction { [[NSNotificationCenter defaultCenter] postNotificationName:kStatusBarTappedNotification object:nil]; } 

Observe la notificación en el controller necesario (por ejemplo, en viewWillAppear):

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarTappedAction:) name:kStatusBarTappedNotification object:nil]; 

Retire el observador correctamente (por ejemplo, en viewDidDisappear):

 [[NSNotificationCenter defaultCenter] removeObserver:self name:kStatusBarTappedNotification object:nil]; 

Implementar callback de event handling notificación:

 - (void)statusBarTappedAction:(NSNotification*)notification { NSLog(@"StatusBar tapped"); //handle StatusBar tap here. } 

Espero que ayude.


Actualización Swift 3

Probado y funciona en iOS 9+.

Declare el nombre de la notificación en algún lugar:

 let statusBarTappedNotification = Notification(name: Notification.Name(rawValue: "statusBarTappedNotification")) 

La barra de estado del seguimiento toca y publica la notificación. Agregue las siguientes líneas a su AppDelegate.swift:

 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) let statusBarRect = UIApplication.shanetworking.statusBarFrame guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return } if statusBarRect.contains(touchPoint) { NotificationCenter.default.post(statusBarTappedNotification) } } 

Observe la notificación donde sea necesario:

 NotificationCenter.default.addObserver(forName: statusBarTappedNotification.name, object: .none, queue: .none) { _ in print("status bar tapped") } 

Entonces esta es mi solución actual, que funciona increíblemente bien. Pero por favor, ven con otras ideas, ya que realmente no me gusta …

  • Agregue una vista de desplazamiento en algún lugar de su vista. Quizás esconderlo o colocarlo debajo de alguna otra vista, etc.
  • Establezca que contentSize sea ​​más grande que los límites.
  • Establezca un contentOffset distinto de cero contentOffset
  • En su controller, ejecute un delegado de scrollview como se muestra a continuación.

Al devolver NO , la vista de desplazamiento nunca se desplaza hacia arriba y se recibe una notificación cada vez que el usuario llega a la barra de estado. Sin embargo, el problema es que esto no funciona con una vista de desplazamiento de contenido "real". (ver pregunta)

 - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { // Do your action here return NO; } 

Agregar esto a su AppDelegate.swift hará lo que desee:

 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { super.touchesBegan(touches, withEvent: event) let events = event!.allTouches() let touch = events!.first let location = touch!.locationInView(self.window) let statusBarFrame = UIApplication.shanetworkingApplication().statusBarFrame if CGRectContainsPoint(statusBarFrame, location) { NSNotificationCenter.defaultCenter().postNotificationName("statusBarSelected", object: nil) } } 

Ahora puede suscribirse al evento donde lo necesite:

 NSNotificationCenter.defaultCenter().addObserverForName("statusBarSelected", object: nil, queue: nil) { event in // scroll to top of a table view self.tableView!.setContentOffset(CGPointZero, animated: true) } 

Encontré una solución mucho mejor que es compatible con iOS7 aquí: http://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up

Agregue este método a su AppDelegate:

 - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]]; if (CGRectContainsPoint([UIApplication shanetworkingApplication].statusBarFrame, location)) { NSLog(@"STATUS BAR TAPPED!"); } } 

Implementé esto agregando una vista UIV clara sobre la barra de estado y luego interceptando los events táctiles

Primero en su aplicación, delegue la aplicación: didFinishLaunchingWithOptions: agregue estas 2 líneas de código:

 self.window.backgroundColor = [UIColor clearColor]; self.window.windowLevel = UIWindowLevelStatusBar+1.f; 

Luego, en el controller de vista, desea interceptar los toques de la barra de estado (o en el delegado de la aplicación) agregue el siguiente código

 UIView* statusBarInterceptView = [[[UIView alloc] initWithFrame:[UIApplication shanetworkingApplication].statusBarFrame] autorelease]; statusBarInterceptView.backgroundColor = [UIColor clearColor]; UITapGestureRecognizer* tapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(statusBarClicked)] autorelease]; [statusBarInterceptView addGestureRecognizer:tapRecognizer]; [[[UIApplication shanetworkingApplication].delegate window] addSubview:statusBarInterceptView]; 

En el selector statusBarClicked, haz lo que debas hacer, en mi caso publiqué una notificación en el centro de notifications para que otros controlleres de vista puedan responder a la barra de estado.

Gracias, Max, tu solución funcionó para mí después de pasar años buscando.

Para información :

 dummyScrollView = [[UIScrollView alloc] init]; dummyScrollView.delegate = self; [view addSubview:dummyScrollView]; [view sendSubviewToBack:dummyScrollView]; 

entonces

  dummyScrollView.contentSize = CGSizeMake(view.frame.size.width, view.frame.size.height+200); // scroll it a bit, otherwise scrollViewShouldScrollToTop not called dummyScrollView.contentOffset = CGPointMake(0, 1); //delegate : - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView { // DETECTED! - do what you need to NSLog(@"scrollViewShouldScrollToTop"); return NO; } 

Tenga en count que también tuve una UIWebView que tuve que piratear un poco con una solución que encontré en algún lado:

 - (void)webViewDidFinishLoad:(UIWebView *)wv { [super webViewDidFinishLoad:wv]; UIScrollView *scroller = (UIScrollView *)[[webView subviews] objectAtIndex:0]; if ([scroller respondsToSelector:@selector(setScrollEnabled:)]) scroller.scrollEnabled = NO; } 

Puede rastrear la barra de estado pulsando usando el siguiente código:

 [[NSNotificationCenter defaultCenter] addObserverForName:@"_UIApplicationSystemGestureStateChangedNotification" object:nil queue:nil usingBlock:^(NSNotification *note) { NSLog(@"Status bar pressed!"); }]; 

Una forma, podría no ser la mejor, podría ser poner una UIView clara encima de la barra de estado e interceptar los toques de UIView, podría ayudarte si no aparece nada más …

Si solo está tratando de hacer que UIScrollView desplace hacia arriba cuando se toca la barra de estado, vale la pena señalar que este es el comportamiento pnetworkingeterminado SI su controller de vista tiene exactamente un UIScrollView en sus subviews que tiene scrollsToTop establecido en YES .

Así que tuve que search cualquier otra UIScrollView (o subclasss: UITableView , UICollectionView , y configurar scrollsToTop para ser NO .

Para ser justos, encontré esta información en la publicación que estaba vinculada a la pregunta original, pero también se descarta porque ya no funciona, así que la omití y solo encontré la pieza relevante en una búsqueda posterior.

Use una UIScrollView invisible. Probado en iOS 10 y Swift 3.

 override func viewDidLoad() { let scrollView = UIScrollView() scrollView.bounds = view.bounds scrollView.contentOffset.y = 1 scrollView.contentSize.height = view.bounds.height + 1 scrollView.delegate = self view.addSubview(scrollView) } func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { debugPrint("status bar tapped") return false }