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

Правильный способ скрыть строку состояния в iOS, с анимацией и изменением размера корневого представления

Рассмотрим контроллер вида, который должен выскочить (или скрыть) строку состояния при нажатии кнопки.

- (void) buttonClick:(id)sender
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES
                                            withAnimation:UIStatusBarAnimationSlide];
}

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

Я ожидал, что корневой вид будет расширяться в пространстве, которое ранее использовалось в строке состояния (анимированное, с той же продолжительностью, что и анимация строки состояния).

Каков правильный способ сделать это?

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

Подход "грубой силы"

Очевидно, что следующие работы...

[[UIApplication sharedApplication] setStatusBarHidden:YES
                                        withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    CGRect frame = self.view.frame;
    frame.origin.y -= 20;
    frame.size.height += 20;
    self.view.frame = frame;
}];

... но имеет недостатки:

  • Жесткие коды: продолжительность анимации слайдов
  • Жестко кодирует высоту строки состояния
  • Начало корневого представления остается на (0, -20). Мне нравятся мои кадры для начала (0,0), когда это возможно.

Что я уже пробовал

  • Убедитесь, что маска авторазрешения корневого представления имеет UIViewAutoresizingFlexibleTopMargin и UIViewAutoresizingFlexibleHeight.
  • Вызывается [self.view setNeedsLayout] после скрытия строки состояния.
  • Вызывается [self.view setNeedsDisplay] после скрытия строки состояния.
  • Установите wantsFullScreenLayout в YES до и после скрытия строки состояния.
4b9b3361

Ответ 1

Это прекрасно работает и не имеет ничего жестко закодированного.

CGRect appFrame = [[UIScreen mainScreen] applicationFrame];

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[UIView animateWithDuration:0.25 animations:^{
    self.navigationController.navigationBar.frame = self.navigationController.navigationBar.bounds;
    self.view.window.frame = CGRectMake(0, 0, appFrame.size.width, appFrame.size.height);
}];

Ответ 2

Для тех, кто пытается реализовать это с появлением строки состояния на основе контроллера, вам необходимо реализовать метод prefersStatusBarHidden в контроллере просмотра

 - (BOOL)prefersStatusBarHidden
{
    // If self.statusBarHidden is TRUE, return YES. If FALSE, return NO.
    return (self.statusBarHidden) ? YES : NO;
}

И затем в методе нажатия кнопки:

- (void) buttonClick:(id)sender
{
    // Switch BOOL value
    self.statusBarHidden = (self.statusBarHidden) ? NO : YES;

    // Update the status bar
    [UIView animateWithDuration:0.25 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
    }];
}

Чтобы установить стиль анимации, вы используете это:

-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
{
    return UIStatusBarAnimationSlide;
}

И чтобы настроить стиль:

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Ответ 3

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

- (void)toggleStatusBar {
    BOOL isStatusBarHidden = [[UIApplication sharedApplication] isStatusBarHidden];
    [[UIApplication sharedApplication] setStatusBarHidden:!isStatusBarHidden];

    UIViewController *vc = [[UIViewController alloc] init];
    [self presentViewController:vc animated:NO completion:nil];
    [self dismissViewControllerAnimated:NO completion:nil];
    [vc release];
}

Я использовал этот код в методе "willAnimateRotationToInterfaceOrientation" для альбомной ориентации, и все работает правильно. Но я не знаю, будет ли это работать с анимацией.

Ответ 4

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

-(void)statusBar:(BOOL)status {
UIViewController *rootViewController = self.view.window.rootViewController;
UIView *view = rootViewController.view;

// Hide/Unhide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:status]; // BOOL : YES or NO

// statusBar frame
CGRect statusBarFrame = [UIApplication.sharedApplication statusBarFrame];
// Establish baseline frame
CGRect newViewFrame = self.view.window.bounds;

// Check statusBar frame is worth dodging
if (!CGRectEqualToRect(statusBarFrame, CGRectZero)) {
    UIInterfaceOrientation currentOrientation = rootViewController.interfaceOrientation;
    if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
        // If portrait need to shrink height
        newViewFrame.size.height -= statusBarFrame.size.height;
        if (currentOrientation == UIInterfaceOrientationPortrait) {
            // If not upside-down move down origin
            newViewFrame.origin.y += statusBarFrame.size.height;
        }
    } else { // Is landscape 
        // portrait shrink width
        newViewFrame.size.width -= statusBarFrame.size.width;
        if (currentOrientation == UIInterfaceOrientationLandscapeLeft) {
            // If the status bar is on the left side of the window move origin
            newViewFrame.origin.x += statusBarFrame.size.width;
        }
    }
}
view.frame = newViewFrame; // pass new frame 
}

метод вызова (сообщение):

 if ([[UIApplication sharedApplication] isStatusBarHidden]) {
        [self statusBar:NO];
 } else {
        [self statusBar:YES];
 }

Ответ 5

Я знаю, что это так, но недостатки также очевидны. Вы можете установить self.wantsFullScreenLayout = YES; в свой viewDidLoad и установить xib файл размером с экран (320x480 и 320x568 для iPhone5). Но это означает, что область под строкой состояния также не видна. И используя этот способ, ваше представление также не будет расширяться при скрытии строки состояния. Вы можете рассмотреть этот путь, если у вас нет чего-то отображаемого в области строки состояния.

Ответ 6

После траты часов эксперимента и поиска ответа; в частности этот ответ. С небольшой настройкой, я успешно сделал это, теперь верхний зазор 20px пропал между переходами!

Предположим, что у нас есть BOOL isStatusBarEnabled ivar, который укажет, нужно ли скрывать строку состояния или нет (например: при доступе к NSUserDefault для проверки boolValueForKey).

Итак, сначала проверяем, является ли статусBar уже скрытым или нет через [[UIApplication sharedApplication] isStatusBarHidden], если он не скрыт (== отображается), мы его спрячем! Иначе, действуйте иначе!

  • Чтобы исправить 20px при отображении статуса, но навигация не будет правильно нажата, просто добавьте 20 пунктов к origin.y из self.navgigationController.navigationBar.frame.

  • Сделайте то же самое, когда мы хотим скрыть строку состояния, просто удалите 20 пунктов в origin.y из self.navgigationController.navigationBar.frame, поэтому просто оставьте это 0.

вот оно!

@implementation SomeViewController {
    BOOL isStatusBarEnabled;
}

// ...

- (void)toggleStatusBar
{
    UINavigationBar *navBar = self.navigationController.navigationBar;

    if ([[UIApplication sharedApplication] isStatusBarHidden]) {

        // Change to regular mode
        // Show status bar
        [[UIApplication sharedApplication] setStatusBarHidden:NO
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.3
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.origin.x, 20, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];

    } else if (![[UIApplication sharedApplication] isStatusBarHidden]) {
        // Change to fullscreen mode
        // Hide status bar
        [[UIApplication sharedApplication] setStatusBarHidden:YES
                                                withAnimation:UIStatusBarAnimationSlide];
        [UIView animateWithDuration:0.4
                         animations:^{
                             navBar.frame = CGRectMake(navBar.frame.origin.x, 0, navBar.frame.size.width, navBar.frame.size.height);
                         } completion:nil];
    }

}

// ...

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

// ...

- (void)onDefaultsChanged:(NSNotification*)aNotification
{

    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
    isStatusBarEnabled = [standardDefaults boolForKey:kStatusBar];

    if (isStatusBarEnabled) {

      if ([[UIApplication sharedApplication] isStatusBarHidden]) {

          // Change to regular mode
          // Show status bar
          [self toggleStatusBar];   

    } else {

        // Change to fullscreen mode
        // Hide status bar
        [self toggleStatusBar];

  }

  // ...
}

что это!