如何检测状态栏中的触摸

我在我的应用程序中可以由用户滚动自定义视图。 但是,这个视图不会从UIScrollViewinheritance。 现在,我希望用户能够将此视图滚动到顶部,就像任何其他可滚动视图允许的一样。 我觉得没有直接的办法。

谷歌提出了一个解决scheme: http : //cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html这不再适用于iOS 4.x. 这是一个不行。

我有创build一个scrollview并保持在某处的想法,只是为了赶上它的通知,然后转发他们到我的控制。 这不是解决我的问题的好方法,所以我正在寻找“更清洁”的解决scheme。 我喜欢前面提到的UIApplication子类的链接的一般方法。 但是什么API可以给我可靠的信息?

有什么想法,帮助等等?

编辑:另一件我不喜欢我当前的解决scheme是只有当前的视图没有任何滚动视图。 滚动到顶部的手势只在正好有一个滚动视图时才起作用。 一旦添加了虚拟物(请参阅下面的答案以获取详细信息)以另一个滚动视图查看视图,手势将完全禁用。 寻找更好的解决scheme的另一个原因是…

最后,我从这里回答了工作解决scheme。 感谢你们。

在某处(例如AppDelegate.h)声明通知名称:

static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification"; 

将以下几行添加到您的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 sharedApplication].statusBarFrame; if (CGRectContainsPoint(statusBarFrame, location)) { [self statusBarTouchedAction]; } } - (void)statusBarTouchedAction { [[NSNotificationCenter defaultCenter] postNotificationName:kStatusBarTappedNotification object:nil]; } 

观察所需控制器中的通知(例如,在viewWillAppear中):

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

正确移除观察者(例如在viewDidDisappear中):

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

实现通知处理callback:

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

希望它会有所帮助。


Swift 3更新

经过testing,适用于iOS 9+。

在某处声明通知名称:

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

跟踪状态栏触摸并发布通知。 将以下几行添加到您的AppDelegate.swift中:

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

必要时注意通知:

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

所以这是我目前的解决scheme,它工作得非常好。 但请与其他想法,因为我不喜欢它…

  • 在您的视图中添加一个滚动视图。 也许把它藏起来,或者把它放在其他一些视图下
  • contentSize设置为大于边界
  • 设置一个非零的contentOffset
  • 在你的控制器中实现如下所示的滚动视图的委托。

通过总是返回NO ,滚动视图永远不会滚动,每当用户点击状态栏,就会得到一个通知。 但问题是,这不适用于“真正的”内容滚动视图。 (见问题)

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

添加到你的AppDelegate.swift将做你想要的:

 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.sharedApplication().statusBarFrame if CGRectContainsPoint(statusBarFrame, location) { NSNotificationCenter.defaultCenter().postNotificationName("statusBarSelected", object: nil) } } 

现在,您可以订阅您需要的活动:

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

find一个更好的解决scheme,这是iOS7兼容在这里: http ://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up

将此方法添加到您的AppDelegate中:

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

我通过在状态栏上添加一个清晰的UIView来实现这一点,然后拦截触摸事件

首先在你的应用程序委托应用程序中:didFinishLaunchingWithOptions:添加这两行代码:

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

然后在视图控制器中,你想拦截状态栏的水龙头(或在应用程序委托)添加以下代码

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

在statusBarClickedselect器,做你需要做的,在我的情况下,我发布了通知中心的通知,以便其他视图控制器可以响应状​​态栏的水龙头。

谢谢麦克斯,你的解决scheme为我工作了很长时间后。

有关信息:

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

然后

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

请注意,我有一个UIWebView也是我必须破解我find的某个解决scheme:

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

您可以使用以下代码跟踪状态栏的点按:

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

一种方式,可能不是最好的,可以是在状态栏顶部放置一个清晰的UIView,并截取UIView的触摸,如果没有其他的东西出现,可能会帮助你。

如果你只是试图让UIScrollView在状态栏被点击的时候滚动到顶部,值得注意的是这是默认的行为,如果你的视图控制器在它的子视图中只有一个UIScrollView ,那么scrollsToTop设置为YES

所以我只需要去find其他的UIScrollView (或者子类: UITableViewUICollectionView ,并且设置scrollsToTopNO

公平的说,我在原帖中find了这个信息,但是也被解雇了,所以我跳过了它,只是在后续的search中find了相关的内容。

使用一个不可见的UIScrollView 。 在iOS 10和Swift 3testing

 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 }