代码之家  ›  专栏  ›  技术社区  ›  Max Seelemann

如何在状态栏中检测触摸

  •  31
  • Max Seelemann  · 技术社区  · 15 年前

    我的应用程序中有自定义视图,用户可以滚动查看。但是,此视图不是从UIScrollView继承的。现在我希望用户能够滚动这个视图到顶部,就像任何其他可滚动视图所允许的那样。我想没有直接的办法。

    http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html

    我的想法是创建一个scrollview并把它放在某个地方,只是为了捕捉它的通知,然后将它们转发给我的控件。这不是一个很好的方法来解决我的问题,所以我正在寻找“清洁”的解决办法。我喜欢前面提到的链接到UIApplication子类的一般方法。但是什么API能给我可靠的信息呢?

    有什么想法、帮助等吗。。。?

    我不喜欢当前解决方案的另一点是,它只在当前视图没有任何滚动视图的情况下工作。只有在只有一个滚动视图的情况下,“滚动到顶部”手势才起作用。一旦虚拟对象被添加到另一个scrollview视图中(详见下面我的答案),这个手势就被完全禁用了。寻找更好解决方案的另一个原因。。。

    10 回复  |  直到 15 年前
        1
  •  52
  •   Eugene Tartakovsky    8 年前

    最后,我根据这里的答案整理出了有效的解决方案。谢谢你们。

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

    static NSString * const kStatusBarTappedNotification = @"statusBarTappedNotification";
    

    #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];
    

    正确移除观察者(例如,在视图中):

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

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

    希望能有帮助。


    Swift 3更新

    在iOS9+上测试并运行。

    在某处声明通知名称:

    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")
    }
    
        2
  •  43
  •   Trenton McKinney ivirshup    6 年前

    这是我目前的解决方案,效果非常好。但请你带上其他的想法,因为我不太喜欢。。。

    • 在视图中的某处添加滚动视图。或者把它藏起来,或者放在其他地方。
    • 设置其 contentSize
    • 设置非零 contentOffset
    • 在您的控制器中,实现如下所示的scrollview的委托。

    总是回来 NO ,滚动视图从不向上滚动,每当用户点击状态栏时就会收到通知。然而,问题是,这不适用于“真正的”内容滚动视图。(见问题)

    - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
    {
        // Do your action here
        return NO;
    }
    
        3
  •  15
  •   DTHENG    10 年前

    将此添加到您的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)
    }
    
        4
  •  11
  •   Stunner    10 年前

    找到了一个更好的解决方案,它与iOS7兼容: http://ruiaureliano.tumblr.com/post/37260346960/uitableview-tap-status-bar-to-scroll-up

    - (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!");
        }
    }
    
        5
  •  10
  •   manggit    13 年前

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

    应用程序中的第一个代理ap应用程序:使用选项完成启动:添加这两行代码:

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

    在statusBarClicked选择器中,执行您需要执行的操作,在我的示例中,我向通知中心发布了一个通知,以便其他视图控制器可以响应状态栏点击。

        6
  •  9
  •   JohnDugdale    14 年前

    谢谢,麦克斯,你的解决方案在我花了很长时间寻找之后对我有效。

    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,我不得不用我在某处找到的一个解决方案进行一些修改:

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

    UIScrollView

    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
    }
    
        8
  •  4
  •   Aron Balog    12 年前

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

    [[NSNotificationCenter defaultCenter] addObserverForName:@"_UIApplicationSystemGestureStateChangedNotification"
                                                      object:nil
                                                       queue:nil
                                                  usingBlock:^(NSNotification *note) {
            NSLog(@"Status bar pressed!");
    }];
    
        9
  •  1
  •   Daniel    15 年前

        10
  •  1
  •   apb    11 年前

    如果你只是想 UIScrollView 视图控制器正好有一个 在其子视图中 scrollsToTop 设置为 YES

    UIScrollView公司 (或子类: UITableView , UICollectionView ,并设置 滚动桌面 成为 NO .

    post that was linked to 在原来的问题,但它也被驳回,因为不再工作,所以我跳过它,只找到了后续搜索相关的一块。

        11
  •  1
  •   jcesarmobile    5 年前

    对于iOS 13来说,这对我来说很有效,Objective-C类别 UIStatusBarManager

    @implementation UIStatusBarManager (CAPHandleTapAction)
    -(void)handleTapAction:(id)arg1 {
        // Your code here
    }
    @end