アプリにUITabBar
があり、この行をA ppDelegateに配置することで、最初のタブの最初のUIViewController
に非表示にしています。
// ... 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
を非表示にした後、適切にバーを表示するにはどうすればよいですか?
前もって感謝します。
これはhidesBottomBarWhenPushed
のドキュメントが言っていることです(強調が追加されました):
はいの場合、下部のバーは非表示のままですView Controllerがスタックからポップされるまで
したがって、表示されている動作は、ドキュメントに記載されているとおりの動作であるように見えます。まず、hidesBottomBarWhenPushed = YES
を持つスタックにViewControllerをプッシュします。その時点で、他のView Controllerをスタックにプッシュしても、下部のバーの非表示は変更されません。その最初のViewControllerがスタック上にある限り、下部のバーは非表示のままになります。
したがって、UIの目標を達成するための別の方法を考え出す必要があると思います。 1つのオプションは、最初のビューコントローラーをタブバーコントローラーのビュー上にモーダルビューコントローラーとして表示することです。次に、2番目のView Controllerに移動する場合は、最初のViewControllerを閉じてください。視覚的な違いは、トランジションアニメーションだけです。
確かに他の選択肢もありますが、それが最初に頭に浮かびました。
幸運を!
これはしばらくの間私を悩ませてきた問題であり、私はうまくいく解決策を見つけただけです。 hidesBottomBarWhenPushed
プロパティは非常に奇妙な獣であり、私の考えでは、直感に反する方法で機能します。
それに関する問題は、新しいビューコントローラーをプッシュする(またはポップバックする)と、navigationControllerがallビューコントローラー(上から下へ)に下のバーを非表示にするかどうかを尋ねるということです。 any彼らのYES
はタブバーが非表示になると言っています。そのため、NO
を新しいViewControllerで非表示に設定しても、タブバーは非表示のままになります。
これが私の解決策です-タブバーを持たせたくないビューコントローラーのhidesBottomBarWhenPushed
ゲッターをオーバーライドし、それがスタックの一番上にあるかどうかを確認します。
Objective-C
- (BOOL) hidesBottomBarWhenPushed
{
return (self.navigationController.topViewController == self);
}
Swift(それほど明白ではないため、スニペット)
override var hidesBottomBarWhenPushed: Bool {
get {
return navigationController?.topViewController == self
}
set {
super.hidesBottomBarWhenPushed = newValue
}
}
これにより、非表示/表示ロジックが1つの場所にうまくカプセル化されるため、非表示を行うビューコントローラーの外部でそれについて考える必要はありません。
同じ問題が発生しましたが、3時間後に解決策が見つかりました!このトピックで 2010年10月8日に回答 、デイブ・バトンは次のように述べています。
hidesBottomBarWhenPushedプロパティを使用する正しい方法は次のとおりです。
self.anotherViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:self.anotherViewController animated:animated];
これに対する解決策が見つかったかどうかはわかりませんが、私はこれを機能させることができました。
私のシナリオ:
UITabBarController
に4つのタブバーアイテムがあります。タブバーアイテムの1つに、ボタンが付いた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;
}
シミュレーターでこれについていくつかの簡単なテストを実行しましたが、正常に機能しているようです。
一部の寄稿者は、これは悪いUIであると示唆していますが、私は現在、これがどのように機能するかを確認するために試しています。
フィードバックを(警官)喜んで受け取ります。 :)
使用する
secondViewController.hidesBottomBarWhenPushed = NO;
いくつかの操作を挿入するとき
firstViewController.hidesBottomBarWhenPushed = YES;
あなたはhidesBottomBarWhenPushedの使用法を誤解したと思います。はいの場合、View Controllerがスタックからポップされるまで、下部のバーは非表示のままになります。
だから私があなたの質問を正しく理解しているなら:
SecondViewControllerはYESである必要があり、firstViewControllerはNOである必要があります。
UINavigationController
をサブクラス化することで、これを解決する非常に簡単な方法を見つけました。オブジェクトが関連付けられたカテゴリを使用しても同じことができますが、すでにサブクラスがあるので、そこにコードを挿入しました。
まず、UINavigationControllerにivarを追加します。
@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
プロパティを使用してセットにデータを入力し、ビューコントローラーレベルで値をリセットします(ビューコントローラーにこのプロパティが設定されている場合、その上にあるすべてのものも非表示になるため)。簡単にするために、ルートビューコントローラーを使用して、セット内の値に基づいてタブバーの表示と非表示を制御します。
また、どこかでセットを初期化する必要があります。私はinitWithRootViewController:
を使用しました。
これは私にとっては非常にシームレスに機能し、既存のアニメーションを引き継いだり、エッジケースを処理したりすることなく、これを行うために考えられる最もハックの少ない方法です。
これは私のために働きます。ここにある他のスレッドのヒントのおかげで、1つのビューコントローラーのタブバーのみを非表示にし、内部から呼び出されるビューコントローラーに対してタブバーを再確立するソリューションを見つけました。
そうすることで、ナビゲーションコントローラーの通常のチェーンを維持できます。
これは私が最終的に得たものです:
#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つの副作用がありますが、これは皆さんから隠したくありません。 1.このナビゲーションコントローラーから呼び出し元のナビゲーションコントローラーに戻ると、デバイスが1回回転するまで、または別のタブが前面に表示された後に関連するタブが再度選択されるまで、呼び出し側コントローラーのステータスバーとナビゲーションバーが重なります。 2.呼び出し元のViewControllerがテーブルビューであり、デバイスがテーブルに戻るときにランドスケープモードの場合、テーブルはランドスケープに適した方向で表示されますが、ポートレートのようにレイアウトされます。左上隅は問題ありませんが、一部のテーブルセルとタブバーは画面の下に隠れています。右側には空き容量があります。これも、デバイスを再度回転させることで修正されます。
これらのマイナーだが厄介なバグの解決策を見つけたら、最新情報をお知らせします。
ビューコントローラを設定
タブバーに画面を設定する必要はありません。この設定画面は過去2つの方法で、画面下部のタブバーに任意の画面をプッシュするように設定します。
override func viewWillAppear(_ animated: Bool) {
self.hidesBottomBarWhenPushed = true
}
override func viewDidAppear(_ animated: Bool) {
self.hidesBottomBarWhenPushed = false
}
ご不明な点がございましたら、お気軽にお問い合わせください。