hidesBottomBarWhenPush = НЕТ не работает? - PullRequest
25 голосов
/ 13 апреля 2011

У меня в приложении UITabBar, который я прячу на первой UIViewController в первой вкладке, поместив эту строку в A ppDelegate :

// ... in MyAppDelegate.m
firstViewController.hidesBottomBarWhenPushed = YES;

В firstViewController пользователь может нажать UIButton, который выдвигает новый UIViewController в той же вкладке. Я бы хотел, чтобы UITabBar снова было видно, когда это произойдет. Я пытаюсь заставить его вернуться так:

//... in firstViewController.m

secondViewController = [[SecondViewController alloc] init];
secondViewController.hidesBottomBarWhenPushed = NO;
[[self navigationController] pushViewController:secondViewController animated:YES];

К сожалению, не возвращает UITabBar. Он остается скрытым.

Как правильно выставить бар UITabBar после его сокрытия?

Заранее спасибо.

Ответы [ 9 ]

67 голосов
/ 24 апреля 2014

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

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

Вот мое решение - переопределить геттер hidesBottomBarWhenPushed в контроллере представления, для которого вы не хотите иметь панель вкладок, и проверьте, находится ли он на вершине стека:

Objective-C

- (BOOL) hidesBottomBarWhenPushed
{
    return (self.navigationController.topViewController == self);
}

Свифт (не так очевидно, отсюда и фрагмент)

override var hidesBottomBarWhenPushed: Bool {
    get {
        return navigationController?.topViewController == self
    }
    set {
        super.hidesBottomBarWhenPushed = newValue
    }
}

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

28 голосов
/ 13 апреля 2011

Это то, что сказано в документации для hidesBottomBarWhenPushed (выделение добавлено):

Если ДА, нижняя панель остается скрытой до тех пор, пока контроллер представления не выскочит из стека.

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

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

Конечно, есть и другие варианты, но они мне в голову пришли.

Удачи!

9 голосов
/ 14 июня 2016

У меня была такая же проблема, но через 3 часа мне нашли решение!В этой теме ответил 8 октября '10 , Дейв Баттон сказал:

Правильный способ использования hidesBottomBarWhenPressed Свойство:

self.anotherViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:self.anotherViewController animated:animated];
2 голосов
/ 05 августа 2011

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

Мой сценарий:

У меня есть UITabBarController с 4 элементами панели вкладок. На один из элементов панели вкладок загружается UIViewController с кнопками на нем. Кнопки вызывают функцию IBOutlet, которая загружает другую UIViewController, которая содержит панель вкладок внизу.

После многих проб и ошибок ........

В функции IBOutlet я делаю следующее:

{
 self.hidesBottomBarWhenPushed = YES;
 /* Push the new controller with tab bar */
}

Это работало нормально, когда панель вкладок UITabBarController's сдвигалась влево, а моя панель вкладок от перемещенного контроллера скользила вправо.

Очевидно, что с точки зрения функциональности мне нужно отодвинуть начальную барную строку UITabBarController's обратно при «возвращении».

После многих проб и ошибок ........

У меня есть метод viewWillDisappear в UIViewController, который выдвигает UIViewController с панелью вкладок как:

- (void) viewWillDisappear:(BOOL)animated
{
    self.hidesBottomBarWhenPushed = NO;
}

Я провел несколько быстрых тестов в симуляторе, и, похоже, он работает нормально.

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

Рад получить (коп) любые отзывы. :)

1 голос
/ 04 марта 2014

Я нашел действительно простой способ решить эту проблему с помощью подкласса UINavigationController.Вы можете сделать то же самое, используя категорию со связанным объектом, но у меня уже был подкласс, поэтому я просто добавил туда код.

Сначала вы добавляете ivar в свой UINavigationController:

@interface CustomNavigationController ()
{
    NSMutableSet *_viewControllersWithHiddenBottomBar;
}

@end

Затем я переопределил методы push и pop для обработки логики сокрытия:

- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if(viewController.hidesBottomBarWhenPushed)
    {
        viewController.hidesBottomBarWhenPushed = NO;
        [_viewControllersWithHiddenBottomBar addObject:viewController];
        [self rootViewController].hidesBottomBarWhenPushed = YES;
    }
    else
    {
        [self rootViewController].hidesBottomBarWhenPushed = NO;
    }
    [super pushViewController:viewController animated:animated];
}

- (UIViewController *) popViewControllerAnimated:(BOOL)animated
{
    if([_viewControllersWithHiddenBottomBar containsObject:self.viewControllers[self.viewControllers.count - 2]])
    {
        [self rootViewController].hidesBottomBarWhenPushed = YES;
    }
    else
    {
        [self rootViewController].hidesBottomBarWhenPushed = NO;
    }
    UIViewController *poppedViewController = [super popViewControllerAnimated:animated];
    [_viewControllersWithHiddenBottomBar removeObject:poppedViewController];
    return poppedViewController;
}

- (UIViewController *) rootViewController
{
    return ((UIViewController *)self.viewControllers.firstObject);
}

Я использую свойство hidesButtomBarWhenPushed для заполнения набора, а затем сбрасываю значение на уровне viewcontroller (поскольку, если какой-либо контроллер представления имеет это свойство, все, что находится сверху, также будет скрыто).Чтобы упростить задачу, я использую корневой viewcontroller для управления отображением и скрытием панели вкладок на основе значений в наборе.

Вам также нужно где-то инициализировать набор, я просто использовал initWithRootViewController:.

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

1 голос
/ 06 апреля 2012

Использование

secondViewController.hidesBottomBarWhenPushed = NO;

При вставке некоторых операций

firstViewController.hidesBottomBarWhenPushed = YES;
1 голос
/ 13 апреля 2011

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

Так что, если я правильно понимаю ваш вопрос:

ВторойViewController должен быть ДА, первыйViewController должен быть НЕТ.

0 голосов
/ 14 ноября 2018

Установите View контроллер в

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

override func viewWillAppear(_ animated: Bool) {

     self.hidesBottomBarWhenPushed = true
}

override func viewDidAppear(_ animated: Bool) {

    self.hidesBottomBarWhenPushed = false
}

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

0 голосов
/ 07 января 2012

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

Поступая так, я могу поддерживать регулярную цепочку навигационных контроллеров.

Вот что я наконец получил:

#define kTabBarHeight               49 // This may be different on retina screens. Frankly, I have not yet tried.

- (void) hideTabBar:(BOOL)hide {

    // fetch the app delegate
    AppDelegate         *delegate   = [[UIApplication sharedApplication] delegate];

    // get the device coordinates
    CGRect              bounds      = [UIScreen mainScreen].bounds;
    float               width;
    float               height;

    // Apparently the tab bar controller's view works with device coordinates  
    // and not with normal view/sub view coordinates
    // Therefore the following statement works for all orientations. 
    width                   = bounds.size.width;
    height                  = bounds.size.height;

    if (hide) {

        // The tab bar should be hidden too. 
        // Otherwise it may flickr up a moment upon rotation or 
        // upon return from detail view controllers. 
        [self.tabBarController.tabBar setHidden:YES];

        // Hiding alone is not sufficient. Hiding alone would leave us with an unusable black
        // bar on the bottom of the size of the tab bar. 
        // We need to enlarge the tab bar controller's view by the height of the tab bar. 
        // Doing so the tab bar, although hidden, appears just beneath the screen. 
        // As the tab bar controller's view works in device coordinations, we need to enlarge 
        // it by the tab bar height in the appropriate direction (height in portrait and width in landscape)
        // and in reverse/upside down orientation we need to shift the area's origin beyond zero. 
        switch (delegate.tabBarController.interfaceOrientation) {
            case UIInterfaceOrientationPortrait:
                // Easy going. Just add the space on the bottom.
                [self.tabBarController.view setFrame:CGRectMake(0,0,width,height+kTabBarHeight)];
                break;

            case UIInterfaceOrientationPortraitUpsideDown:
                // The bottom is now up! Add the appropriate space and shift the rect's origin to y = -49
                [self.tabBarController.view setFrame:CGRectMake(0,-kTabBarHeight,width,height+kTabBarHeight)];
                break;

            case UIInterfaceOrientationLandscapeLeft:
                // Same as Portrait but add the space to the with but the height
                [self.tabBarController.view setFrame:CGRectMake(0,0,width+kTabBarHeight,height)];
                break;

            case UIInterfaceOrientationLandscapeRight:
                // Similar to Upside Down: Add the space and shift the rect. Just use x and with this time
                [self.tabBarController.view setFrame:CGRectMake(0-kTabBarHeight,0,width+kTabBarHeight,height)];
                break;

            default:
                break;
        }
    } else {
        // reset everything to its original state. 
        [self.tabBarController.view setFrame:CGRectMake(0,0,width,height)];
        [self.tabBarController.tabBar setHidden:NO];
    }

    return; 
}


- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{

    // It is important to call this method at all and to call it here and not in willRotateToInterfaceOrientation
    // Otherwise the tab bar will re-appear. 
    [self hideTabBar:YES];

    // You may want to re-arrange any other views according to the new orientation
    // You could, of course, utilize willRotateToInterfaceOrientation instead for your subViews. 
}

- (void)viewWillAppear: (BOOL)animated { 

    // In my app I want to hide the status bar and navigation bar too. 
    // You may not want to do that. If so then skip the next two lines. 
    self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];

    [self hideTabBar: YES];

    // You may want to re-arrange your subviews here. 
    // Orientation may have changed while detail view controllers were visible. 
    // This method is called upon return from pushed and pulled view controllers.   

    return;
}

- (void)viewWillDisappear: (BOOL)animated {     

    // This method is called while this view controller is pulled
    // or when a sub view controller is pushed and becomes visible
    // Therefore the original settings for the tab bar, navigation bar and status bar need to be re-instated

    [self hideTabBar:NO];

    // If you did not change the appearance of the navigation and status bar in viewWillAppear,
    // then you can skip the next two statements too. 
    self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];

    return;
}

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

Существует один побочный эффект в сочетании с сокрытием строки состояния и панели навигации, которые я не хочу скрывать от вас, ребята. 1. При возврате из этого контроллера навигации к вызывающему навигационному контроллеру строка состояния и панель навигации на вызывающем контроллере перекрываются, пока устройство не будет повернуто один раз или пока соответствующая вкладка не будет выбрана снова после того, как другая вкладка окажется впереди. 2. Когда вызывающий контроллер представления является табличным представлением и когда устройство находится в горизонтальном режиме при возврате к таблице, тогда таблица отображается в соответствующей ориентации для альбомной ориентации, но она размещается так, как если бы она была портретной. Верхний левый угол в порядке, но некоторые ячейки таблицы плюс панель вкладок скрыты под экраном. На правой стороне есть свободное место. Это тоже можно исправить, повернув устройство снова.

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

...