Подтвердить что ты не робот

Как обнаружить штрихи в строке состояния

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

Добавление этого в ваш 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

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

Ответ 5

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

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

Ответ 6

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

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

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

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

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

Ответ 8

Используйте невидимый 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
}

Ответ 9

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

Ответ 10

Если вы просто пытаетесь прокручивать UIScrollView вверху, когда отображается строка состояния, стоит отметить, что это поведение по умолчанию IF ваш контроллер представления имеет ровно один UIScrollView в своем subviews, для которого scrollsToTop установлено значение YES.

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

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