web-dev-qa-db-ja.com

UINavigationControllerに設定されたhidesBarsOnSwipeを使用してステータスバーがコンテンツと重複しないようにする方法

IOS 8に追加された新しい機能を使用しようとしています-ユーザーがテーブルビューをスクロールしている間はナビゲーションバーを非表示にします(モバイルSafariの場合と同様)。 hidesBarsOnSwipeのプロパティUINavigationControllerYESviewDidAppearメソッドでUITableViewControllerに設定しています:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if([self.navigationController respondsToSelector:@selector(hidesBarsOnSwipe)]) {
        self.navigationController.hidesBarsOnSwipe = YES;
    }
}

ビューがスクロールされると、ナビゲーションバーが非表示になります。ここまでは順調ですね。しかし、ステータスバーはまだ表示されており、テーブルビューの内容はそれを通して見えますが、見苦しいです:

enter image description here

edgesForExtendedLayoutUIEdgeRectNoneに設定するか、Table ViewのcontentInsetを調整しようとしましたが、役に立ちませんでした。ナビゲーションバーとともにステータスバーを非表示にする、または不透明にする他のソリューションはありますか?

34
Michał Ciuba

Anasの答えを基に、実用的なソリューションがあります(tableViewControllerUITableViewControllerインスタンスであると仮定しています):

UINavigationControllerサブクラス(または潜在的にtableViewControllerからも):

- (void)viewDidLoad {
    if ([self respondsToSelector:@selector(barHideOnSwipeGestureRecognizer)]) {
        // iOS 8+
        self.hidesBarsOnSwipe = YES;
        [self.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipe:)];
    }
}

- (void)swipe:(UISwipeGestureRecognizer *)recognizer {
    BOOL shouldHideStatusBar = self.navigationController.navigationBar.frame.Origin.y < 0;
    tableViewController.hideStatusBar = shouldHideStatusBar;
    [UIView animateWithDuration:0.2 animations:^{
        [tableViewController setNeedsStatusBarAppearanceUpdate];
    }];
}

tableViewControllerで:

@property(nonatomic, getter = shouldHideStatusBar) BOOL hideStatusBar;

- (BOOL)prefersStatusBarHidden {
    return [self shouldHideStatusBar];
}

これがうまくいかない場合はお知らせください。いくつかの非自明なこと:

  • self.navigationController.navigationBar.frame.Origin.yは、非表示の場合は-44(ナビゲーションバーの負の高さ)、表示の場合は20(ステータスバーの高さ)でした。アニメーションの間でも中間にはなかったため、負の値==非表示および非負の値==が表示されます。
  • 子View Controllerは、ステータスバーを非表示にするかどうかを照会するものです。私の場合、UIViewController内のUINavigationController内にUITabBarControllerがあり、prefersStatusBarHiddenUIViewControllerをオーバーライドするまで機能しませんでした。
  • 非表示のステータスバーにはフレームがないため、アニメーションブロックでsetNeedsStatusBarAppearanceUpdateの呼び出しをラップしない限り、コンテンツは20ポイント上昇する可能性があります。
  • 構文が正しいことを願っています。これをSwiftコードからバックポートしました。
30
Andrew

実際、それは非常に簡単です。ナビゲーションisNavigationBarHiddenプロパティをステータスバーに接続するだけです。

Objective-C

- (BOOL)prefersStatusBarHidden {
    return self.navigationController.isNavigationBarHidden;
}

Swift <= 2.

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}

Swift 3.

override var prefersStatusBarHidden: Bool {
    return navigationController?.isNavigationBarHidden ?? false
}

また、アプリケーションの.plistファイルに「View Controller-based status bar Appearance」=「YES」があることを確認してください。

39
iOSergey

その新しいプロパティにはbarHideOnSwipeGestureRecognizerが付いています。

INavigationController Class Reference から:

必要に応じてジェスチャレコグナイザーに変更を加えることができますが、デリゲートを変更してはなりません。また、デフォルトのターゲットオブジェクトと、それに設定されているアクションを削除しないでください。プロパティをオーバーライドしてこのジェスチャ認識機能を置き換えようとしないでください。

ただし、ターゲットをaddできます:

[self.navigationController setHidesBarsOnSwipe:YES];
[self.navigationController.barHideOnSwipeGestureRecognizer addTarget:self action:@selector(swipeGesture:)];

...そして、コールバックであなたがやりたいことをします:

- (void)swipeGesture:(UIPanGestureRecognizer*)gesture
{
    // Tweak the status bar
}

ジェスチャの状態を手動で切り替えたり、ステータスバーを非表示/表示するタイミングを見つけたりする必要があるかもしれません。

8
Anas

@iOSergeyからの答えは完璧に機能します!

Swift 1.2のソリューションを次に示します。次のコードをビューの.Swiftファイルに追加します。

override func prefersStatusBarHidden() -> Bool {

    return self.navigationController!.navigationBarHidden as Bool

}

アニメーションでステータスバーを非表示にする場合:

override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
    return .Slide
}

override func prefersStatusBarHidden() -> Bool {
    return navigationController?.navigationBarHidden ?? false
}
3
Tai Le

多くの苦労の末、ようやくこれを解決することができました。

  1. TableViewControllerをUIViewControllerに変更します
  2. TableViewをUIViewControllerにドラッグし、main.storyboardのナビゲーションバーのすぐ下に配置します。
  3. 不足している制約を追加します。
  4. テーブルビューをクリックして、制約を調べます
  5. 下部のスペースを設定:スーパービューを0
  6. スーパービューの末尾スペースを0に設定します
  7. スーパービューの先頭スペースを0に設定します
  8. 「上部に揃える:上部レイアウトガイド。上部に0を設定します(非常に重要)」

次のコードをUIViewControllerのviewDidLoad関数に追加します。

//ステータスバーの無地の背景を作成(in Swift Code)

let statusFrame = CGRectMake(0.0、0、self.view.bounds.size.width、
UIApplication.sharedApplication()。statusBarFrame.size.height)

var statusBar = UIView(frame:statusFrame)

statusBar.backgroundColor = UIColor.whiteColor()

self.view.addSubview(statusBar)

あなたがしているのは、ナビゲーションバーのすぐ下に実線のバーを作成することです。ナビゲーションバーが上に移動すると、ソリッドバーも上に移動し、ステータスバーのすぐ後ろに移動します。

唯一の問題は、画面を横向きに回転させると、ステータスバーが消えても白いバーがそこにあることです。

2
John Chen

OK barHideOnSwipeGestureRecognizerがあります。したがって、対応するUIPanGestureのリスナーを作成できます。ナビゲーションバーが非表示の場合、そのy Originは-44.0であることに注意してください。それ以外の場合は0です(ステータスバーを非表示にしているため、20ではありません!)。

View Controller(Swift 2)で:

 // Declare at beginning
var curFramePosition: Double!
var showStatusBar: Bool = true
self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")

...

override func viewDidLoad(){
    self.navigationController?.hidesBarsOnSwipe = true
  curFramePosition = 0.0 // Not hidden
  self.navigationController?.barHideOnSwipeGestureRecognizer.addTarget(self, action: "didSwipe:")
  ...
}

func didSwipe(swipe: UIPanGestureRecognizer){
    // Visible to hidden
    if curFramePosition == 0 && self.navigationController?.navigationBar.frame.Origin.y == -44 {
        curFramePosition = -44
        showStatusBar = false
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
    // Hidden to visible
    else if curFramePosition == -44 && self.navigationController?.navigationBar.frame.Origin.y == 0 {
        curFramePosition = 0
        showStatusBar = true
        prefersStatusBarHidden()
        setNeedsStatusBarAppearanceUpdate()
    }
}

override func prefersStatusBarHidden() -> Bool {
    if showStatusBar{
        return false
    }
    return true
}
1
goodcow

別の方法は、別のビュー(tableviewまたはcollectionviewまたはwebviewまたはscrollviewなど)を追加し、ビューの上部の制約を「Superview.Top」に、下部の制約を「Top Layout Guide.Bottom」に設定するだけです。ビューの背景色とthats、それはあなたもコードなしでInterface Builderでそれをすべて行うことができます。また、そのイベントに応答する場合は、ビューの境界変更にキーパスオブザーバーを追加するか、ビューをサブクラス化してその境界セッターをオーバーライドできます...

0
Oleg Sherman

ナビゲーションisNavigationBarHiddenプロパティをステータスバーに接続する必要があります。

    return self.navigationController.isNavigationBarHidden;
0