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

На iOS 7 нажатие на контроллер с панелью инструментов оставляет пробел неиспользуемого пространства, если он в конечном итоге содержится в контроллере панели вкладок

В моем приложении iOS мое окно rootViewController - это контроллер панели вкладок с такой иерархией, как это:

  • UITabBarController
    • UINavigationController 1
      • FirstContentController
    • UINavigationController 2
      • ...
    • UINavigationController 3
      • ...
    • ...

Когда пользователь удаляет определенную строку на FirstContentController, экземпляр SecondController будет нажат на его навигационный контроллер. SecondContentController устанавливает hidesBottomBarWhenPushed в YES в свой метод init и устанавливает self.navigationController.toolbarHidden в NO в viewWillAppear:.

В iOS 6 пользователь будет использовать строку в FirstController, а SecondController будет нажата на навигационный контроллер. Поскольку он имеет hidesBottomBarWhenPushed, он скроет панель вкладок, и к моменту завершения анимации перехода SecondController появится на экране с видимой панелью инструментов.

Однако при тестировании этого в iOS 7 поведение hidesBottomBarWhenPushed, похоже, изменилось. Теперь я вижу:

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

Разрыв полностью непригодный - он не реагирует на касания, и если я устанавливаю clipsToBounds на YES на главном экране, ничего не рисует. После много отладки и изучения иерархии подзаголовков это выглядит так: механизм автозамены iOS изменяет размер представления контроллера вида на высоту 411 (на iPhone 5). Это должно быть 460, чтобы дойти до панели инструментов, но система компоновки, похоже, включает в себя панель "призраков" с 49-пиксельной высотой.

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

На iOS 7, как я могу заставить панель вкладок исчезнуть, и панель инструментов легко встанет на место, когда новый контроллер будет нажат, и все еще есть представление, занимающее все пространство между элементом навигации и панелью инструментов?

ОБНОВЛЕНИЕ

После дальнейшего исследования это произойдет, только если для параметра SecondController edgesForExtendedLayout установлено значение UIRectEdgeNone. Однако, если я не установил это свойство в UIRectEdgeNone, рамка представления слишком длинная и расширяется под панелью инструментов, где ее невозможно увидеть или взаимодействовать с ней.

4b9b3361

Ответ 1

Снимите флажок "Скрыть нижние бары при нажатии" и установите свои автоподстановки так, как будто есть панель вкладок. Затем в "ViewDidLoad" контроллера вы хотите скрыть панель вкладок системы, поместите следующий код.

[self.tabBarController.tabBar setFrame:CGRectZero];

Это гарантирует, что панель вкладок все еще принимает пользовательское взаимодействие, которое пока не отображается пользователям. (другие альтернативы, такие как установка 0 альфа или скрытый, будут отображаться в полосе вкладок бесполезно). Теперь автоконкретарии будут следить за тем, чтобы ваше представление отображалось правильно с высотой полосы табуляции как ноль.

Ответ 2

Я обнаружил, что добавление следующих 2 строк кода в viewDidLoad SecondViewController (где вы хотите скрыть TabBar, но покажете панель инструментов) устраняет проблему.

self.extendedLayoutIncludesOpaqueBars = YES;
self.edgesForExtendedLayout = UIRectEdgeBottom;

My viewDidLoad SecondViewController выглядит следующим образом:

- (void)viewDidLoad {
    [super viewDidLoad];
    // These 2 lines made the difference
    self.extendedLayoutIncludesOpaqueBars = YES;
    self.edgesForExtendedLayout = UIRectEdgeBottom;

    // The usual configuration
    self.navigationController.navigationBar.barStyle = UIBarStyleBlack;
    self.navigationController.navigationBar.translucent = NO;

    self.navigationController.toolbarHidden = NO;
    self.navigationController.toolbar.barStyle = UIBarStyleBlack;
    self.navigationController.toolbar.translucent = NO;
    .
    .
}

Но вам нужно зафиксировать рамку представления вручную, так как это приведет к размеру (320x504). Это означает, что он распространяется даже за панель инструментов. Если это не беспокоит вас, тогда это решение должно работать.

Ответ 3

Вам не понравится этот ответ Это не тот ответ, который вы хотите, но после некоторых исследований по скрытию панели вкладок в iOS7, мой вывод: не делать!

Брекеты таблеток никогда не предназначались для скрытия - ведь для чего нужно UITabBarController, если вы хотите скрыть панель вкладок. Контроллеры hidesBottomBarWhenPushed для просмотра скрывают нижнюю панель навигационного контроллера, а не панели вкладок. Из документации:

Контроллер представления, добавленный в качестве дочернего элемента навигационного контроллера, может отображать дополнительную панель инструментов в нижней части экрана. Значение этого свойства на верхнем контроллере представления определяет, видна ли панель инструментов. Если значение этого свойства равно YES, панель скрыта. Если значение этого свойства равно NO, панель отображается.

Кроме того, вы не можете напрямую изменять объект панели вкладок. Опять же, из документации:

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

Это именно то, что вы делаете, когда устанавливаете его в скрытое.

В iOS6 это сработало, но теперь в iOS7 это не так. И, похоже, очень склонна скрыть это. Когда вам удастся скрыть его, если приложение перейдет на задний план и вернется, Apple layout logic переопределит ваши изменения.

Мое предложение состоит в том, чтобы отображать ваши данные по-разному. В iOS7 вы можете создавать настраиваемые переходы, поэтому, если для вас важно иметь переход на push, вы можете воссоздать его самостоятельно, хотя это немного выше. Обычный модальный переход - это то, что пользователи знакомы, и на самом деле подходит для этого случая лучше, чем push, который скрывает панель вкладок.


Другим решением является использование панели инструментов вместо панели вкладок. Если вы используете панель инструментов навигационного контроллера для своих вкладок, вы можете использовать hidesBottomBarWhenPushed по мере необходимости, и это даст вам поведение, которое вы ожидаете.

Ответ 4

Это ошибка в iOS 7 UIKit из-за этой конкретной комбинации:

  • UITabBarController
  • hidesBottomBarWhenPushed = YES
  • edgeForExtendedLayout = UIRectEdgeNone
  • Панель инструментов UINavigationController

Вы должны указать ошибку с Apple и включить код примера.

Чтобы обойти ошибку, вам нужно удалить одно из этих четырех условий. Два возможных варианта:

  • Исправьте расположение вашего "второго" контроллера вида, чтобы он работал правильно, когда edgesForExtendedLayout установлено на UIRectEdgeAll. Это может быть так же просто, как установка contentInset в режиме прокрутки.

  • Не используйте встроенную панель инструментов UINavigationController. Вместо этого создайте отдельный экземпляр UIToolBar и вручную добавьте его во второй вид контроллера представления.

Ответ 5

Вам нужно установить tabBar от TabBarController до hidden, и ваше представление должно иметь autosizing для гибкой высоты.

С помощью этого кода он работает:

@implementation SecondController

-(id)init
{
    if( (self = [super init]) )
    {
    }

    return self;
}

- (void)viewDidLoad;
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    self.tabBarController.tabBar.hidden = YES;
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // will log a height of 411, instead of the desired 460
    NSLog(@"frame: %@", NSStringFromCGRect(self.view.frame));
}

@end

Или, если вы хотите использовать метод hidesBottomBarWhenPushed, вы должны сделать это до, вы явно нажимаете на контроллер представления:

-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
    SecondController* controller = [[SecondController alloc] init];
    controller.hidesBottomBarWhenPushed = YES;

    [self.navigationController pushViewController:controller animated:YES];
}

Если вы используете второй метод, ваш метод viewDidLoad может избавиться от гибкого метода высоты, а также tabBarHidden:

- (void)viewDidLoad;
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    self.edgesForExtendedLayout = UIRectEdgeNone;
}

Посмотрите результат:

enter image description here

Ответ 6

Ключом к этой загадке является то, что размер navigationcontroller.view.frame не изменяется. Переход от баткина Gist здесь представляет собой мой собственный.

FirstViewController.m

#import "FirstController.h"
#import "SecondController.h"

@implementation FirstController

-(id)init
{
    if( (self = [super init]) )
    {
        self.tabBarItem.title = @"Foo";
        self.tabBarItem.image = [UIImage imageNamed:@"Tab Icon.png"];
    }

    return self;
}

-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
    UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];

    cell.textLabel.text = @"Click";

    return cell;
}

-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
    SecondController* controller = [[SecondController alloc] init];
    self.tabBarController.tabBar.hidden = YES;
    [self.navigationController pushViewController:controller animated:YES];
}

@end

SecondViewController.m

#import "SecondController.h"

@implementation SecondController

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.view.backgroundColor = [UIColor redColor];
    self.view.clipsToBounds = YES;

    /* ENTER VORTEX OF DESPAIR */

    // without this, there no gap, but the view continues under the tool 
    // bar; with it, I get the 49-pixel gap thats making my life miserable

    self.edgesForExtendedLayout = UIRectEdgeNone;

    //this resizes the navigation controller to fill the void left by the tab bar.
    CGRect newFrame = self.navigationController.view.frame;
    newFrame.size.height = newFrame.size.height + 49;
    self.navigationController.view.frame = newFrame;

    /* EXIT VORTEX OF DESPAIR */

    self.navigationController.toolbarItems = @[
                                               [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:nil action:nil]
                                               ];


}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    self.navigationController.toolbarHidden = NO;

    // will log a height of 411, instead of the desired 460
    NSLog(@"frame: %@", NSStringFromCGRect(self.view.frame));
    NSLog(@"frame: %@", NSStringFromCGRect(self.navigationController.view.frame));
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.tabBarController.tabBar.hidden = NO;
    self.navigationController.toolbarHidden = YES;

    //this resizes the navigation controller back to normal.
    CGRect newFrame = self.navigationController.view.frame;
    newFrame.size.height = newFrame.size.height - 49;
    self.navigationController.view.frame = newFrame;

    //this is optional and resizes the view to fill the void left by the missing toolbar.
    CGRect newViewFrame = self.view.frame;
    newViewFrame.size.height = newViewFrame.size.height + 49;
    self.view.frame = newViewFrame;

}

@end

Ответ 7

Если вы используете автоматический макет, убедитесь, что вы привязываете представление к его супервизору, а не к руководству Top Layout Guide или Bottom Layout Guide.

Ответ 8

Вы пытались переместить свой вызов hidesBottomBarWhenPushed в viewDidLoad или до того, как нажата кнопка secondViewController?

С ios7 возникает много проблем с синхронизацией, если вы не выполняете вызовы в подходящий момент.

Ответ 9

Вы упомянули, что можете исправить это, не касаясь edgesForExtendedLayout. Есть ли необходимость в том, что контент/элементы управления контроллера вида содержатся в корневом представлении контроллера толкаемого представления? Вы можете рассмотреть возможность упаковки всего в представление, которое является первым и единственным дочерним элементом основного представления. Затем отрегулируйте этот ракурс в viewDidLayoutSubviews контроллера толкаемого представления, чтобы избежать постоянного содержания содержимого под панелью инструментов, используя верхний/нижний LayoutGuide контроллера вида.

Ответ 10

Я построил новый проект, используя ваш Gist, и я заключил UITabBarController в UINavigationController:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    UITabBarController* tabController = [[UITabBarController alloc] init];

    tabController.viewControllers = @[
                                      [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc] init]],
                                      [[UINavigationController alloc] initWithRootViewController:[[FirstViewController alloc] init]]
                                      ];

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:tabController];
    [navController setNavigationBarHidden:YES];
    self.window.rootViewController = navController;

    return YES;
}

И чтобы показать SecondViewController, вот что я сделал:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    SecondViewController* controller = [[SecondViewController alloc] init];

    // Reaching the UITabBarViewController parent navigationController
    [self.parentViewController.navigationController pushViewController:controller animated:YES];
}

Наконец, в secondViewController:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.view.backgroundColor = [UIColor redColor];
    self.view.clipsToBounds = YES;

    // The following line only works in iOS7
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }

    [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:nil action:nil]];

    UIBarButtonItem * logoutButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemReply target:nil action:nil];
    NSMutableArray * arr = [NSMutableArray arrayWithObjects:logoutButton, nil];
    [self setToolbarItems:arr animated:YES];


    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [self.navigationController setToolbarHidden:NO animated:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [self.navigationController setToolbarHidden:YES animated:YES];
}

Вот что он выглядит: 3rd tentative

EDIT: Изменен пример и изменился снимок экрана. Сделал пример совместимым с iOS6.

Ответ 11

Я вручную управляю скрытой/скрытой нижней панелью вкладок вместе с анимацией затухания

 ...

[self.tabBarController.tabBar setHidden:NO];

[self.tabBarController.tabBar setAlpha:0.1];
[UIView animateWithDuration:0.2 animations:^{
    [self.tabBarController.tabBar setAlpha:1.0];
}];
 ...

Нижняя панель инструментов SecondVC была добавлена ​​в IB. Пока нет проблем. Использование раскадровки.

Ответ 12

Я думаю, вы можете установить edgeController edgeForExtendedLayout в UIRectEdgeBottom.

Ответ 13

Это помогает мне: Выберите контроллер просмотра в раскадровке → Перейти к свойствам → Снимите флажок "Настроить вставки прокрутки"

Ответ 14

Как указывает @Leo Natan, кажется, что скрытие панели вкладок и показ панели инструментов не рекомендуется. Тем не менее, есть очень простое решение, которое работает:

Просто проверьте "Under Opaque Bars" в свойствах контроллера представления в раскадровке, как показано ниже: