web-dev-qa-db-ja.com

iOS 7では、ツールバーでコントローラーを押すと、最終的にTab Bar Controllerに含まれる場合、使用できないスペースのギャップが残ります

私のiOSアプリでは、私のウィンドウのrootViewControllerは、次のような階層を持つTab Bar Controllerです。

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

ユーザーがFirstContentControllerの特定の行をタップすると、SecondControllerのインスタンスがNavigation Controllerにプッシュされます。 SecondContentControllerは、hidesBottomBarWhenPushedメソッドでYESinitに設定し、self.navigationController.toolbarHiddenからNOviewWillAppear:

IOS 6では、ユーザーはFirstControllerの行をタップし、SecondControllerはnavコントローラーにプッシュされます。 hidesBottomBarWhenPushedが設定されているため、タブバーが非表示になり、遷移アニメーションが完了するまでに、SecondControllerがツールバーに表示された状態で画面に表示されます。

ただし、iOS 7でこれをテストすると、hidesBottomBarWhenPushedの動作が変更されたようです。私が今見ているのは:

  • 期待どおりにタブバーが非表示になります
  • 期待どおりにツールバーが表示されます
  • ツールバーとコンテンツビューの間に、49ピクセルの高さ(タブバーの高さ)の使用できないスペースのギャップが表示されます。

ギャップは完全に使用できません-タッチに応答せず、メインビューでclipsToBoundsをYESに設定しても、何も描画されません。多くのデバッグとサブビュー階層の調査の後、iOSの自動サイズ調整メカニズムにより、View Controllerのビューのサイズが411(iPhone 5上)に変更されたように見えます。ツールバーに至るまで460に達するはずですが、レイアウトシステムには「ゴースト」の49ピクセルの高さのタブバーが含まれているようです。

この問題は、View ControllerのTab Bar Controllerが親コンテナである場合にのみ発生します。

IOS 7では、新しいコントローラーが押されたときにタブバーが消え、ツールバーがシームレスに所定の位置にスライドし、ビューがナビゲーション項目とツールバーの間のスペース全体を占めるようにする方法はありますか?

[〜#〜] update [〜#〜]

さらに調査した結果、SecondControllerのedgesForExtendedLayoutUIRectEdgeNoneに設定されている場合にのみ発生します。ただし、そのプロパティをUIRectEdgeNoneに設定しない限り、ビューのフレームは長すぎてツールバーの下に表示されるため、表示したり操作したりすることはできません。

39
Bill

[プッシュ時にボトムバーを非表示にする]のチェックを外し、タブバーがあるかのように自動制約を設定します。次に、システムタブバーを非表示にするコントローラーの「ViewDidLoad」に、次のコードを配置します。

[self.tabBarController.tabBar setFrame:CGRectZero];

これにより、タブバーはユーザーの操作を受け入れますが、ユーザーには表示されません。 (アルファ値を0に設定したり、非表示にしたりすると、タブバーは役に立たなくなります)autoconstaraintsは、タブバーの高さをゼロとしてビューが正しく表示されるようにします。

8
Ah Ryun Moon

SecondViewControllerのviewDidLoad(TabBarを非表示にし、ツールバーを表示する)に次の2行のコードを追加すると、問題が解決することがわかりました。

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

SecondViewControllerの私のviewDidLoadは次のとおりです。

- (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)になるため、ビューのフレームを手動で修正する必要があります。これは、ツールバーの背後にも拡張されることを意味します。これが問題にならない場合は、このソリューションが機能するはずです。

19
srik

この答えは気に入らないでしょう これはあなたが望む答えではありませんが、iOS7でタブバーを隠すことに関するいくつかの調査の後、私の結論は次のとおりです:do n't!

タブバーを非表示にするつもりはありませんでした-結局、タブバーを非表示にしたいのであれば、なぜUITabBarControllerがあります。 View ControllerのhidesBottomBarWhenPushedは、TabバーではなくNavigation Controllerの下部バーを非表示にするためのものです。ドキュメントから:

a navigation controllerの子として追加されたView Controllerは、画面の下部にオプションのツールバーを表示できます。一番上のView Controllerのこのプロパティの値は、ツールバーが表示されるかどうかを決定します。このプロパティの値がYESの場合、toolbarは非表示です。このプロパティの値がNOの場合、バーは表示されます。

さらに、タブバーオブジェクトを直接変更しないように警告されます。繰り返しますが、ドキュメントから:

このプロパティに保存されているUITabBarオブジェクト自体を操作しようとしないでください。

これは、非表示に設定するときに実行していることとまったく同じです。

IOS6ではこれは機能していましたが、現在iOS7では機能していません。そして、それを隠すのは非常に間違いやすいようです。最終的に非表示にしたときに、アプリがバックグラウンドに戻って戻ると、Appleのレイアウトロジックが変更をオーバーライドします。

私の提案は、データをモーダルに表示することです。 iOS7では、カスタムトランジションを作成できます。そのため、プッシュトランジションを持つことが重要な場合は、自分でそれを再作成できますが、これは少し上です。通常のモーダルトランジションはユーザーがよく知っているものであり、実際にはタブバーを非表示にするプッシュよりもこのケースに適しています。


別の解決策は、タブバーの代わりにツールバーを使用することです。タブにNavigation Controllerのツールバーを使用する場合、必要に応じてhidesBottomBarWhenPushedを使用すると、期待どおりの動作が得られます。

17
Leo Natan

これは、次の特定の組み合わせによるiOS 7 UIKitのバグです。

  • UITabBarController
  • hidesBottomBarWhenPushed = YES
  • edgeForExtendedLayout = UIRectEdgeNone
  • UINavigationControllerツールバー

Appleでバグを報告し、サンプルコードを含める必要があります。

バグを回避するには、これら4つの条件のいずれかを削除する必要があります。考えられる2つのオプション:

  1. 「2番目の」View Controllerのレイアウトを修正して、edgesForExtendedLayoutUIRectEdgeAllに設定されている場合に正しく機能するようにします。これは、スクロールビューでcontentInsetを設定するのと同じくらい簡単です。

  2. UINavigationControllerの組み込みツールバーを使用しないでください。代わりに、別のUIToolBarインスタンスを作成し、2つ目のView Controllerのビューに手動で追加します。

5
Darren

tabBarTabBarControllerhiddenに設定する必要があり、ビューには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メソッドを使用する場合は、これを行う必要がありますbefore you Pushビューコントローラーは明らかに:

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

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

2番目のメソッドを使用する場合、viewDidLoadメソッドは、柔軟なheightメソッドとtabBarHiddenを取り除くことができます。

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

結果を見る:

enter image description here

2
Alexander

この難問の鍵は、navigationcontroller.view.frameサイズが変わらないことです。バトキンの要点はここにある 自分の要点 です。

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's 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
2
Hackmodford

自動レイアウトを使用している場合は、トップレイアウトガイドまたはボトムレイアウトガイドではなく、必ずスーパービューにビューを固定してください。

2
tounaobun

edgesForExtendedLayoutに触れないことでこれを修正できると言います。 View Controllerのコンテンツ/コントロールが、プッシュされたView Controllerのルートビューに含まれている必要な理由はありますか?メインビューの最初で唯一の子であるビューですべてをラップすることを検討できます。次に、プッシュされたView ControllerのviewDidLayoutSubviewsでそのビューのフレームを調整し、View Controllerのtop/bottomLayoutGuideを使用してツールバーの下に永続的にコンテンツが表示されるのを防ぎます。

0
Felix Lamouroux

私は手動でボトムタブバーの非表示/非表示をフェードアニメーションとともに管理します

 ...

[self.tabBarController.tabBar setHidden:NO];

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

SecondVCの下部ツールバーがIBに追加されました。今のところ問題ありません。ストーリーボードを使用します。

0
dklt

これは私を助けます:ストーリーボードでコントローラーの表示を選択します->プロパティに移動->「スクロールインセットの調整」のチェックを外します

0
George

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's 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

編集:サンプルを変更し、スクリーンショットを変更しました。 iOS6の例を互換性のあるものにしました。

0
Rufel

ViewDidLoadで、またはsecondViewControllerがプッシュされる前に、呼び出しhidesBottomBarWhenPushedを移動しようとしましたか?

Ios7では、適切なタイミングで呼び出しを行わないと、多くのタイミングの問題が発生します。

0
Geraud.ch

SecondControllerのedgesForExtendedLayoutをUIRectEdgeBottomに設定できると思います。

0
jianpx