写真アプリの場合と同じように、タップでステータスバーの表示を切り替えたい。
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がそれを行うので、方法がなければなりません。
IOS 7以降のデフォルトでは、特定のView Controllerのステータスバーを非表示にするには、次の手順を実行します。
modalPresentationStyle
がUIModalPresentationFullScreen
でない場合は、手動でmodalPresentationCapturesStatusBarAppearance
をYES
に設定します。提示される前に提示されたコントローラー(例:ストーリーボードを使用している場合は-presentViewController:animated:completion
または-prepareForSegue:
)-prefersStatusBarHidden
をオーバーライドし、適切な値を返しますsetNeedsStatusBarAppearanceUpdate
を呼び出します表示または非表示をアニメーション化する場合は、アニメーションブロック内で手順3を実行します。
[UIView animateWithDuration:0.33 animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
提示されたコントローラーの-preferredStatusBarUpdateAnimation
から適切なUIStatusBarAnimation
値を返すことにより、アニメーションのスタイルを設定することもできます。
最初のセットView controller-based status bar appearance
Info.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()
})
}
}
@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;
}
これはちょっとしたハックと思われるかもしれませんが、効果を再現するのに最も近い方法です。まだ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;
}];
}
}
このコードは完全に正常に機能します。
-(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;
}];
});
}
}
実際には、ナビゲーションバーのフレームをいじる必要があります。 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)]
を確認してください。
これを解決する方法は、アプリの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
メソッドを呼び出すことができます。
フェード時にナビゲーションバーが上にスライドするこの問題を修正するには、次のコードを追加する必要があります。
self.navigationController.navigationBar.frame = CGRectZero;
次のコード行の前の「フェードイン」セクションに移動します。
self.navigationController.navigationBar.frame = CGRectMake(0, 20, barFrame.size.width, 64);
これが必要なのは、フレームが同じであり、同じフレームを設定しても無視され、ナビゲーションバーのスライドが停止しないためです。したがって、フレームを別のフレームに変更してから、正しいフレームに再度設定して変更をトリガーする必要があります。