Barの表示/非表示切り替え(navigationView-scrollView構成)

navigationView の下にscrollViewがあるという構成の場合に
iphone - navigationBar,statusBar,toolBarのOn/Offがされるようにする。表示がOnの場合にも、全画面表示でnavigationBar,statusBar,toolBarが半透明である状態にする。という実装をいろいろなやみながら実装してみました。

初期表示

まず,Viewが表示される前に(=UIViewControllerのviewWillAppear)では、全画面表示をすること(UIViewControllerのwantsFullScreenLayout)の設定を行います

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  // 全画面表示
  self.wantsFullScreenLayout = YES;
}

(以上 5/19追記)

つぎの,Viewが表示されるとき(=UIViewControllerのviewDidAppear)には、各Barに対して以下の設定を行い、それらが表示されないようにしました。

      1. Barの半透明のスタイル設定
      2. Barを非表示にする設定
      3. 全画面表示をすること(UIViewControllerのwantsFullScreenLayout)
- (void)viewDidAppear:(BOOL)animated {  [super viewDidAppear:animated];

   self.navigationController.toolbarHidden = YES;


  ....
  ScrollView内にView/UIControlの配置をする処理
  ....

  // Navigation Bar, Status Bar, ToolBarのスタイル(透明、黒)


  self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
  [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackTranslucent;
  self.navigationController.toolbar.barStyle = UIBarStyleBlack;
  self.navigationController.toolbar.translucent = YES;
  // Navigation Bar, Status Bar, ToolBarを非表示に
  [UIApplication sharedApplication].statusBarHidden = YES;
  self.navigationController.navigationBar.hidden = YES;
  self.navigationController.toolbarHidden = YES;
....
}

表示/非表示の切り替え

表示/非表示の切り替えには、上記と同様に各表示設定のプロパティ値を指定することにより行えるはず。ということで。

// 表示/非表示の反転
BOOL hidden = !self.navigationController.navigationBar.hidden;
self.navigationController.navigationBar.hidden = hidden;
[[UIApplication sharedApplication] setStatusBarHidden:hidden animated:YES];
[self.navigationController setToolbarHidden:hidden];

表示位置にずれへの対応

以上のようにして、表示の切り替えはできたのだけれど、navigationBarの分なのかtoolBarの分なのかわからないが、下方向に表示座標がずれてしまう。調べてみると描画後にScrollViewの内容を配置するためのInsetとOffset(contentInsetとcontentOffsetプロパティ)がずれてしまいます。そのため一旦UIKitの描画がされた後に、それらのプロパティを初期状態(offsetはx,yとも0,Insetも全て0に)に戻すようにします。その初期状態を戻す処理をメソッドとして定義して、NSObjectで定義されている[performSelectorOnMainThread:withObject:waitUntilDone]でそれを呼び出すことによって行います。

- (void)resetScrollOffsetAndInset:(id)arg {
  PageScrollView *scrollView = (PageScrollView *)self.view;
  UIEdgeInsets inset;
  inset.left = 0;
  inset.right = 0;
  inset.top = 0;
  inset.bottom = 0;
  scrollView.contentInset = inset;
  CGSize size = scrollView.contentSize;
  size.height = self.view.frame.size.height;
  scrollView.contentSize = size;
}


// 表示/非表示の反転
-(void) changeNavigationAndStatusBar {
  BOOL hidden = !self.navigationController.navigationBar.hidden;
  self.navigationController.navigationBar.hidden = hidden;
  [[UIApplication sharedApplication] setStatusBarHidden:hidden animated:YES];
  [self.navigationController setToolbarHidden:hidden];


  // scrollViewのcontentのoffsetとinsetを元の状態に戻す
  [self performSelectorOnMainThread:@selector(resetScrollOffsetAndInset:)
                            withObject:[NSNumber numberWithBool:hidden]
                        waitUntilDone:NO];
}

機器回転時など

機器回転時の対応をする場合なども表示/非表示の反転と同様にScrollViewのContentInsetとcontentOffsetを元に戻すために[performSelectorOnMainThread:withObject:waitUntilDone]の呼び出しが必要でした。

まだまだ課題

初期状態でBarを表示すると、位置がずれてしまうなど、まだ問題ありです。