Как вводить/выводить статусбар и навигационную панель одновременно?

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

Вот как я пытался:

[[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationSlide];
[self.navigationController setNavigationBarHidden:hide animated:animated];

Однако продолжительность обеих анимаций не одинакова. Анимация строки состояния занимает больше времени. Я не нашел способа указать продолжительность анимации. Я пропустил что-то очевидное?


person Ortwin Gentz    schedule 28.06.2010    source источник
comment
Я подал отчет об ошибке в Apple: openradar.appspot.com/8548087 Пожалуйста, обманите его, если вы тоже пострадал.   -  person Ortwin Gentz    schedule 14.10.2010


Ответы (7)


Ответ ios-lizard - это почти то, что я хотел, но панель навигации снова появляется при вращении устройства, если hidden не установлен правильно. Так что это сработало для меня:

Скрытие анимации работает/выглядит красиво YEAH!!.

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

- (void)toggleFullscreen {

    UINavigationBar *navBar = self.navigationController.navigationBar;
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
    float animationDuration;
    if(statusBarFrame.size.height > 20) { // in-call
        animationDuration = 0.5;
    } else { // normal status bar 
        animationDuration = 0.6;
    }

    _fullscreen = !_fullscreen;
    if (_fullscreen) { 
        // Change to fullscreen mode
        // Hide status bar and navigation bar
        [[UIApplication sharedApplication] setStatusBarHidden:YES
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:animationDuration animations:^{
            navBar.frame = CGRectMake(navBar.frame.origin.x,
                                  -navBar.frame.size.height,
                                  navBar.frame.size.width,
                                  navBar.frame.size.height);
        } completion:^(BOOL finished) {
            [self.navigationController setNavigationBarHidden:YES animated:NO];
        }];

    } else {
        // Change to regular mode
        // Show status bar and navigation bar
        [[UIApplication sharedApplication] setStatusBarHidden:NO
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:animationDuration animations:^{
             navBar.frame = CGRectMake(navBar.frame.origin.x,
                                       statusBarFrame.size.height,
                                       navBar.frame.size.width,
                                       navBar.frame.size.height);
        } completion:^(BOOL finished) {
            [self.navigationController setNavigationBarHidden:NO animated:NO];
        }];

    }

}
person nacho4d    schedule 22.02.2012

Вот как я исправил эту проблему для своего приложения.

    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];

    // delta is the amount by which the nav bar will be moved
    delta = statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height;

    if(statusBarFrame.size.height>20) { // in-call
        animationDuration = 0.5;
    }
    else { // normal status bar 
        animationDuration = 0.6;
    }

    // hide status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];

    // hide nav bar
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:animationDuration];

    self.navigationController.navigationBar.frame = CGRectOffset(self.navigationController.navigationBar.frame, 0.0, -delta);

    [UIView commitAnimations];
person ios-lizard    schedule 20.01.2012

Очевидно, что нет простого решения, чтобы сделать это правильно. Apple должна исправить это.

Конечно, одним из обходных путей является использование альфа-затухания, как предлагает Эфраим. Если вы настаиваете на скользящем поведении, я считаю, что лучше просто анимировать панель навигации и скрыть/показать строку состояния без какой-либо анимации. Это выглядит намного лучше, чем скольжение строки состояния, потому что зазор между полосами во время анимации довольно заметен.

person Ortwin Gentz    schedule 14.01.2011

Вот более лаконичный метод, который использует системные константы для продолжительности анимации, а также обрабатывает входящие вызовы.

Обратите внимание, что navigationBar — это выход, а statusBarHeight — плавающая переменная экземпляра.

- (IBAction)toggleControls:(id)sender {
    BOOL isHidden = ! [UIApplication sharedApplication].statusBarHidden;
    if (isHidden)
        statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
    [UIView animateWithDuration:[UIApplication sharedApplication].statusBarOrientationAnimationDuration animations:^{
        self.navigationBar.frame = CGRectMake(self.navigationBar.frame.origin.x,
                                              isHidden ? -self.navigationBar.frame.size.height : statusBarHeight,
                                              self.navigationBar.frame.size.width,
                                              self.navigationBar.frame.size.height);
    }];
    [[UIApplication sharedApplication] setStatusBarHidden:isHidden withAnimation:UIStatusBarAnimationSlide];
}
person ioblomov    schedule 29.04.2013

Ответ nacho4d - это почти то, что я хотел. Но он меняет рамку navBar до того, как navBar становится видимым. Таким образом, мы не можем видеть анимацию перехода. Похоже, что navBar появляется внезапно. Более того, при показе статусBarFrame.size.height равен 0. Вот его код:

[[UIApplication sharedApplication] setStatusBarHidden:NO
                                            withAnimation:UIStatusBarAnimationSlide];
    [UIView animateWithDuration:animationDuration animations:^{
         navBar.frame = CGRectMake(navBar.frame.origin.x,
                                   statusBarFrame.size.height,
                                   navBar.frame.size.width,
                                   navBar.frame.size.height);
    } completion:^(BOOL finished) {
        [self.navigationController setNavigationBarHidden:NO animated:NO];
    }];

при отображении мы хотели бы, чтобы строка состояния скользила вместе с панелью навигации. вот мой ответ:

        UINavigationBar *navBar = self.navigationController.navigationBar;
        [[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:UIStatusBarAnimationSlide];

        [UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            // make navigationBar visual
            if (!hidden)
            {
                [self.navigationController setNavigationBarHidden:hidden animated:NO];
            }

            navBar.frame = CGRectMake(navBar.frame.origin.x,
                                      hidden ? -navBar.frame.size.height : 20,
                                      navBar.frame.size.width,
                                      navBar.frame.size.height);
        } completion:^(BOOL finished) {
            if (hidden)
            {
                [self.navigationController setNavigationBarHidden:hidden animated:NO];
            }
        }];
  1. при скрытии и hidden равно NO. мы должны сначала изменить фрейм navBar, а затем сделать navBar скрытым.
  2. при отображении и скрытый равен YES. мы сначала делаем navBar визуальным, затем меняем кадр.
  3. мы выбираем UIViewAnimationOptionCurveEaseOut, чтобы он выглядел лучше.
person RY_ Zheng    schedule 25.02.2016

Для этого вы можете использовать переменную экземпляра:

self.navigationController setNavigationBarHidden:hide animated:animated];
_shouldHideStatusBar = hide;

И реализовать следующую функцию:

- (BOOL)prefersStatusBarHidden{
    return _shouldHideStatusBar;
}

Функция setNavigationBarHidden:animated автоматически вызывает функцию prefersStatusBarHidden. Если это не так, вы можете вызвать его с помощью следующего метода UIViewController:

[self setNeedsStatusBarAppearanceUpdate];

И, конечно же, вы можете выбрать стиль анимации, скрывающий строку состояния, с помощью:

- (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationSlide;
}
person The Windwaker    schedule 21.08.2014

Это не очень хороший ответ, но он работает. Итак, что я сделал:

// This method gets called by whatever action you want

- (void) toggleShowStatusNavBars:(id)sender {

    // Assuming you have a ivar called barsHidden

    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.4]; // This is IMPORTANT, 0.4s

    self.navigationController.navigationBar.alpha = (barsHidden?1.0:0.0);  

    barsHidden = !barsHidden; 

    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(setStatusBarHidden)];

    [UIView commitAnimations];
}

- (void) setStatusBarHidden {
    [[UIApplication sharedApplication] setStatusBarHidden:barsHidden animated:YES];
}

Это в основном синхронизирует начало анимации (поскольку вы вызываете setStatusBarHidden в начале анимации панели навигации. Ключевой момент заключается в том, что анимация строки состояния занимает 0,4 секунды.

Это работает для меня, но если вы найдете лучший способ, напишите здесь.

person Ephraim    schedule 05.10.2010
comment
Вы скрываете navBar, используя альфа-затухание. Это проще, потому что в этом случае вы можете напрямую манипулировать navBar. В скользящем случае меня интересует, что это нежизнеспособный подход, поскольку navigationController также манипулирует рамкой просмотра содержимого. - person Ortwin Gentz; 14.10.2010