Как обнаружить прикосновения в строке состояния - PullRequest
31 голосов
/ 20 сентября 2010

У меня есть собственное представление в моем приложении, которое может прокручиваться пользователем. Однако это представление не наследуется от UIScrollView. Теперь я хочу, чтобы пользователь мог прокручивать это представление вверх, как это позволяет любое другое прокручиваемое представление. Я понял, что прямого пути для этого нет.

Google нашел одно решение: http://cocoawithlove.com/2009/05/intercepting-status-bar-touches-on.html Это больше не работает на iOS 4.x. Это не пойдет.

У меня была идея создать вид прокрутки и хранить его где-нибудь, просто чтобы перехватить его уведомления, а затем переслать их под мой контроль. Это не хороший способ решить мою проблему, поэтому я ищу "более чистые" решения. Мне нравится общий подход вышеупомянутой ссылки на подкласс UIApplication. Но какой API может дать мне достоверную информацию?

Есть какие-нибудь мысли, помощь и т.д ...?

Редактировать: Еще одна вещь, которая мне не нравится в моем текущем решении, заключается в том, что оно работает только до тех пор, пока у текущего представления нет представлений прокрутки. Жест прокрутки вверх работает только в том случае, если вокруг ровно один вид прокрутки. Как только манекен добавляется (см. Мой ответ ниже) для представления с другим видом прокрутки, жест полностью отключается. Еще одна причина искать лучшее решение ...

Ответы [ 10 ]

50 голосов
/ 23 сентября 2013

Наконец, я собрал рабочее решение из ответов здесь. Спасибо вам, ребята.

Объявите имя уведомления где-нибудь (например, 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];

Реализация обратного вызова обработки уведомлений:

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

Надеюсь, это поможет.


Обновление Swift 3

Протестировано и работает на 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")
}
28 голосов
/ 20 сентября 2010

Так что это мое текущее решение, которое работает на удивление хорошо.Но, пожалуйста, приходите с другими идеями, так как мне это не очень нравится ...

  • Добавьте скролл-просмотр где-нибудь на ваш взгляд.Может быть, скрыть или поместить его под каким-либо другим видом и т. Д.
  • Установите значение contentSize больше границ
  • Установите ненулевое значение contentOffset
  • Inваш контроллер реализует делегат вида прокрутки, как показано ниже.

Всегда возвращая NO, представление прокрутки никогда не прокручивается вверх, и каждый получает уведомление, когда пользователь нажимает на строку состояния.Проблема, однако, в том, что это не работает с «реальным» представлением прокрутки контента.(см. вопрос)

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
    // Do your action here
    return NO;
}
14 голосов
/ 18 сентября 2015

Добавление этого в ваш 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)
}
11 голосов
/ 22 сентября 2013

Нашел гораздо лучшее решение, совместимое с 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!");
    }
}
10 голосов
/ 12 сентября 2012

Я реализовал это, добавив чистый UIView поверх строки состояния и затем перехватывая события касания

Сначала в приложении-делегате приложения: didFinishLaunchingWithOptions: добавьте эти 2 строки кода:

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 делайте то, что вам нужно, в моем случае я отправил уведомление в центр уведомлений, чтобы другие контроллеры представления могли отвечать на нажатие строки состояния.

8 голосов
/ 14 января 2011

Спасибо Макс, ваше решение сработало для меня после долгих лет поиска.

Для информации:

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; 
}
4 голосов
/ 28 мая 2013

Вы можете отслеживать касание строки состояния, используя следующий код:

[[NSNotificationCenter defaultCenter] addObserverForName:@"_UIApplicationSystemGestureStateChangedNotification"
                                                  object:nil
                                                   queue:nil
                                              usingBlock:^(NSNotification *note) {
        NSLog(@"Status bar pressed!");
}];
2 голосов
/ 20 сентября 2016

Используйте невидимку UIScrollView. Протестировано на iOS 10 и 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
}
1 голос
/ 05 сентября 2014

Если вы просто пытаетесь сделать прокрутку UIScrollView к вершине при касании строки состояния, стоит отметить, что это поведение по умолчанию, ЕСЛИ ваш контроллер вида имеет ровно один UIScrollView в своем подпредставления, для которых scrollsToTop установлено на YES.

Так что мне просто нужно было пойти и найти другие UIScrollView (или подклассы: UITableView, UICollectionView, и установить scrollsToTop равным NO.

Честно говоря, я нашел эту информацию в посте , который был связан с в исходном вопросе, но он также был отклонен как не работающий, поэтому я пропустил его и нашел только соответствующий фрагмент в последующем. поиск.

1 голос
/ 20 сентября 2010

Один из способов, возможно, не самый лучший, может заключаться в том, чтобы поместить прозрачный UIView поверх строки состояния и перехватывать прикосновения UIView, может помочь вам, если ничего не появится ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...