web-dev-qa-db-ja.com

iOS7(写真アプリなど)でフェード効果のあるステータスバーを切り替える方法は?

写真アプリの場合と同じように、タップでステータスバーの表示を切り替えたい。

IOS 7より前は、このコードはうまく機能していました。

-(void)setStatusBarIsHidden:(BOOL)statusBarIsHidden {

    _statusBarIsHidden = statusBarIsHidden;

    if (statusBarIsHidden == YES) {

        [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];


    }else{

        [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];

    }

}

しかし、iOS 7で動作させることはできません。私が見つけたすべての回答は、バーを永続的に非表示にするための提案のみを提供し、切り替えはしません。

それでも、Photosがそれを行うので、方法がなければなりません。

13
anna

IOS 7以降のデフォルトでは、特定のView Controllerのステータスバーを非表示にするには、次の手順を実行します。

  1. ステータスバーを非表示にするViewControllerがモーダルで表示されていて、modalPresentationStyleUIModalPresentationFullScreenでない場合は、手動でmodalPresentationCapturesStatusBarAppearanceYESに設定します。提示される前に提示されたコントローラー(例:ストーリーボードを使用している場合は-presentViewController:animated:completionまたは-prepareForSegue:
  2. 提示されたコントローラーの-prefersStatusBarHiddenをオーバーライドし、適切な値を返します
  3. 提示されたコントローラーでsetNeedsStatusBarAppearanceUpdateを呼び出します

表示または非表示をアニメーション化する場合は、アニメーションブロック内で手順3を実行します。

[UIView animateWithDuration:0.33 animations:^{
    [self setNeedsStatusBarAppearanceUpdate];
}];

提示されたコントローラーの-preferredStatusBarUpdateAnimationから適切なUIStatusBarAnimation値を返すことにより、アニメーションのスタイルを設定することもできます。

44
followben

最初のセットView controller-based status bar appearanceInfo.plistからYES

このSwift例は、ボタンを押した後、アニメーションでステータスバーを切り替える方法を示しています。

import UIKit

class ToggleStatusBarViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func prefersStatusBarHidden() -> Bool {
        return !UIApplication.sharedApplication().statusBarHidden
    }

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

    @IBAction func toggleStatusBar(sender: UIButton) {
        UIView.animateWithDuration(0.5,
            animations: {
                self.setNeedsStatusBarAppearanceUpdate()
        })
    }
}
7
coco

@Jonの答えを単純化しても、iOS 7のPhotosアプリと見分けがつかない動作を得ることができました。表示する必要がない場合は、更新が遅れているようです。

- (IBAction)toggleUI:(id)sender {
    self.hidesUI = !self.hidesUI;

    CGRect barFrame = self.navigationController.navigationBar.frame;

    CGFloat alpha = (self.hidesUI) ? 0.0 : 1.0;
    [UIView animateWithDuration:0.33 animations:^{
        [self setNeedsStatusBarAppearanceUpdate];
        self.navigationController.navigationBar.alpha = alpha;
    }];

    self.navigationController.navigationBar.frame = CGRectZero;
    self.navigationController.navigationBar.frame = barFrame;
}

- (BOOL)prefersStatusBarHidden {
    return self.hidesUI;
}
5
Justin Anderson

これはちょっとしたハックと思われるかもしれませんが、効果を再現するのに最も近い方法です。まだ1つの小さな問題があります。フェードアウトすると、ナビゲーションバーのサイズが上から変更されているのがわかります。それは十分に微妙ですが、それでも完全なフェードではありません。誰かがそれを修正する方法を知っているなら、私に知らせてください!

- (BOOL)prefersStatusBarHidden {

    if (_controlsAreHidden == YES)
        return YES;
    else
        return NO;
}

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {

    return UIStatusBarAnimationFade;
}

-(void)setControlsAreHidden:(BOOL)controlsAreHidden {

    _controlsAreHidden = controlsAreHidden;

    if (controlsAreHidden == YES) {

        // fade out
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        [UIView animateWithDuration:0.3 animations:^ {


            [self setNeedsStatusBarAppearanceUpdate];

            self.navigationController.navigationBar.alpha = 0;



        }];


        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 44);



    }else{


        // fade in
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 64);

        [UIView animateWithDuration:0.3 animations:^ {

            [self setNeedsStatusBarAppearanceUpdate];

            self.navigationController.navigationBar.alpha = 1;

        }];


    }

}
4
anna

このコードは完全に正常に機能します。

-(void)setControlsAreHidden:(BOOL)controlsAreHidden {

    if (_controlsAreHidden == controlsAreHidden)
        return;

    _controlsAreHidden = controlsAreHidden;


    UINavigationBar * navigationBar = self.navigationController.navigationBar;

    if (controlsAreHidden == YES) {

        // fade out
        //

        CGRect barFrame = self.navigationController.navigationBar.frame;

        [UIView animateWithDuration:0.3 animations:^ {
            [self setNeedsStatusBarAppearanceUpdate];
            self.navigationController.navigationBar.alpha = 0;
        }];

        self.navigationController.navigationBar.frame = CGRectZero;
        self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 44);

    } else {

        // fade in
        //
        [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^ {
            [self setNeedsStatusBarAppearanceUpdate];
        }];

        double delayInSeconds = 0.01;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

            [self.navigationController setNavigationBarHidden:NO animated:NO];
            navigationBar.alpha = 0;
            [UIView animateWithDuration:UINavigationControllerHideShowBarDuration animations:^ {
                navigationBar.alpha = 1;
            }];

        });

    }

}
3
Jon

実際には、ナビゲーションバーのフレームをいじる必要があります。 2つの別々のアニメーションブロックを使用するだけで、スムーズなアニメーションを実現できます。このようなものは問題なく動作するはずです。

_@property (nonatomic, assign) BOOL controlsShouldBeHidden;

...

- (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated {

    if (self.controlsShouldBeHidden == hidden) {
        return;
    }

    self.controlsShouldBeHidden = hidden;

    NSTimeInterval duration = animated ? 0.3 : 0.0;

    [UIView animateWithDuration:duration animations:^(void) {

        [self setNeedsStatusBarAppearanceUpdate];

    }];

    [UIView animateWithDuration:duration animations:^(void) {

        CGFloat alpha = hidden ? 0 : 1;
        [self.navigationController.navigationBar setAlpha:alpha];

    }];

}

- (BOOL)prefersStatusBarHidden {

    return self.controlsShouldBeHidden;

}
_

IOS 6との互換性については、必ず[self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]を確認してください。

3

これを解決する方法は、アプリのplistの「コントローラーベースのステータスバーの外観を表示する」設定の値によって異なります。

「コントローラーベースのステータスバーの外観を表示する」がplistでNOの場合、次のコードが機能するはずです。

[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];

「ViewControllerベースのステータスバーの外観」がオンになっている場合は、ViewControllerで次のメソッドを追加します。

- (BOOL) prefersStatusBarHidden {
    // I've hardcoded to YES here, but you can return a dynamic value to meet your needs for toggling
    return YES;
}

切り替えの場合、上記のメソッドの値に基づいてステータスバーを非表示にするか表示するかを変更する場合、ViewControllerはsetNeedsStatusBarAppearanceUpdateメソッドを呼び出すことができます。

1
Greg

フェード時にナビゲーションバーが上にスライドするこの問題を修正するには、次のコードを追加する必要があります。

self.navigationController.navigationBar.frame = CGRectZero;

次のコード行の前の「フェードイン」セクションに移動します。

self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 64);

これが必要なのは、フレームが同じであり、同じフレームを設定しても無視され、ナビゲーションバーのスライドが停止しないためです。したがって、フレームを別のフレームに変更してから、正しいフレームに再度設定して変更をトリガーする必要があります。

1
Bond007