HidesBottomBarWhenPushed = NO не работает?

У меня есть UITabBar в моем приложении, которое я прячу на первом UIViewController на первой вкладке, поместив эту строку в 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 после ее спрятать?

Спасибо заранее.

Ответ 1

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

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

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

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

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

Удачи!

Ответ 2

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

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

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

Objective-C

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

Swift (не столь очевидный, следовательно, фрагмент)

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

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

Ответ 3

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

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

self.anotherViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:self.anotherViewController animated:animated];

Ответ 4

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

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

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

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

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

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

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

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

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

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

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

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

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

С удовольствием получаю (полицейские) любые отзывы.:)

Ответ 5

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

Итак, если я правильно понял ваш вопрос:

SecondViewController должен быть YES, firstViewController должен быть NO.

Ответ 6

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

secondViewController.hidesBottomBarWhenPushed = NO;

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

firstViewController.hidesBottomBarWhenPushed = YES;

Ответ 7

Я разработал очень простой способ решить это путем подкласса 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 для заполнения набора, а затем reset значение на уровне viewcontroller (поскольку, если в любом контроллере представления установлено это свойство, все поверх него также будет скрыто). Чтобы сделать все просто, я использую root viewcontroller для управления отображением и скрытием вкладки на основе значений в наборе.

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

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

Ответ 8

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

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

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

#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 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 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 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 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 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. Когда контроллер вызывающего вида представляет собой представление таблицы и когда устройство находится в ландшафтном режиме при возврате в таблицу, таблица отображается в соответствующей ориентации для пейзажа, но она выкладывается, как если бы она была портретом. Верхний левый угол хорош, но некоторые ячейки таблицы плюс панель вкладок скрыты под экраном. С правой стороны есть некоторое свободное пространство. Это также фиксируется поворотом устройства снова.

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