オープンソースこねこね

Webプログラミングなどについてあれこれ。

iOSでステータスバーの色が写真取得すると黒に戻る件についての対処

ステータスバーの文字の色を

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

で白に変えられる。ところがUIImagePickerControllerで写真アルバムから写真を取得すると、このステータスバーの文字色が黒に戻ってしまう。調べたらstackoverflowが引っかかり、以下のワークアラウンドで回避できることがわかったのでメモ。

まずUIImagePickerControllerのデリゲートを設定し

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;

そして以下のデリゲートメソッドを実装する。

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}

UIImagePickerControllerはUINavigationControllerの子クラスなので、UINavigationControllerのデリゲートメソッドであるwillShowViewControllerを実装しておく。ここに色を白にするコードを入れておいてデリゲートにセットしておけばOKというわけです。

以下、stackoverflowの元記事です。

ios7 - UIImagePickerController breaks status bar appearance - Stack Overflow

Codeから遷移したUIViewControllerにstoryboard上でナビゲーションバーを表示する

storyboad上のSegueで画面遷移をつないでいった場合、UINavigationControllerに含まれるViewControllerは自動でナビゲーションバーが表示されて、そこにタイトルとかバーボタンをとかを配置することができるのだけど、コードから遷移させた場合storyboad上ではどことも繋がっていないViewControllerとして表現されてしまって、実際はUINavigationControllerの中にいてナビゲーションバーとかがあるのにそれが表示されていない、ということが起こる。

そんなViewControllerの場合以下のようにしてやればstoryboard上にナビゲーションバーを表示でき、IB上でタイトルやボタンを配置することができます。

  • storyboard上でViewControllerを選択する。
  • Attributes inspectorでSimulated Metrics設定のTop BarTranslucent Navigation Barに設定する
  • storyboard上にナビゲーションバーの領域があらわれる
  • ナビゲーションバーの領域にNavigation Itemドラッグアンドドロップして配置する

以上。

UITextFieldやUITextViewでキーボードの外をタップしたらキーボードを閉じる

すでにいろいろやり方がネット上に書かれているが、自分の中では以下の方法に落ち着いたのでメモっておく。

まず、以下の記事で紹介されているようなFirstResponderを取得するメソッドをUIViewにカテゴリとして事前に実装しておく。

FirstResponderを探せ - Kazzzの日記

#import "UIView+UIUtil.h"
@implementation UIView (UIUtil)
- (UIView *)findFirstResponder
{
    if ([self isFirstResponder]) 
    {
        return self;
    }
    for (UIView *subView in [self subviews]) 
    {
        if ([subView isFirstResponder])
        {
            return subView;
        }
        if ([subView findFirstResponder])
        {
            return [subView findFirstResponder];
        }
    }
    return nil;
}
@end

あとはViewController上で以下のように実装する。

# XXHogeViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    // タップを検知するためのGestureRecognizer。デリゲートで処理するように設定
    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] init];
    gestureRecognizer.delegate = self;
    gestureRecognizer.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:gestureRecognizer];
}

// タップ時のデリゲートメソッド
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    UIView *touchedView = touch.view;
    UIView *firstResponderView = [self.view findFirstResponder];
    
    if (touchedView != firstResponderView) {
        // 現在編集中のViewと違う場所がタップされたときのみキーボードを閉じる
        [self.view endEditing:YES];
    }
    return YES;
}

UIPageViewControllerをUINavigationControllerにいれたらナビゲーションバー部分に潜り込まなくなった件

iOS8でUIPageViewControllerトランジションスタイルをUIPageViewControllerTransitionStyleScrollにしたときのみ発生する。。。マジなんなのこれ。。。しかも一度でも画面をタップすると、潜り込む(正常な)位置に移動するという。挙動が奇妙すぎてStack Overflowでも見つからないし。iOS8のバグを疑ってしまう。ヾ(`Д´)ノ"

f:id:kohkimakimoto:20141203064908g:plain

このサンプルはXcodePage-Based Applicationが作った雛形のプロジェクトを元に、RootViewControllerをNavigationControllerにいれる、のとUIPageViewControllerの初期化処理を以下のようにUIPageViewControllerTransitionStyleScrollを指定するように変えたもの。

self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];

表示されるViewのframeなどを調べてみてもx=0,y=0となっていて変なところはない。それでViewの階層を見てみたらこんな感じになっている。 なんか下にズレてる。。。

f:id:kohkimakimoto:20141203065549p:plain

_UIQueuingScrollViewというViewの位置がy=-64.0という謎な状態になっていて、その子となるViewがその分だけ下にずれている。 しかもこれviewWillAppear:などのフェーズでは確認できず、viewDidAppear:まで到達して初めてこの状態になる。

というわけで以下のようなワークアラウンドを入れた。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)) {
        for (UIView *v in self.pageViewController.view.subviews){
            if ([v isKindOfClass:[UIScrollView class]]) {
                UIScrollView *scv = (UIScrollView *)v;
                CGPoint offset = scv.contentOffset;
                if (offset.y < 0) {
                    offset.y = 0;
                    scv.contentOffset = offset;
                }
            }
        }
    }
}

iOS8の場合、UIPageViewControllerUIScrollViewをとってきてマイナス値なら0に書き換えるということをやっています。これでなんとか対応できた。

追記

コメント欄でアドバイスをいただいて「UIPageViewControllerのAdjust Scroll View Insetsのチェックを外す」で対応できることがわかりました。

xcode6でViewのconstraintに-16がついてiOS7.1でレイアウトがずれる件

xcode6でビューを重ねている状態で、子のビューを親のビューの端にぴったりあわせるるために、オートレイアウトを指定するとなぜかHorizontal Spaceに-16が設定される。しかもこれをiOS8で動かすと綺麗に端がぴったりあって表示されるのに、iOS7.1で動かすとずれて表示されるという状態に。

これがiOS8で

f:id:kohkimakimoto:20141113120025p:plain

こっちがiOS7.1

f:id:kohkimakimoto:20141113120030p:plain

青い領域が子のViewでconstraintが指定してある。青いViewの中にあるテキストフィールドがずれてしまっているが判るだろう。ついでに画面上にピッタリつけたはずの部分にも隙間ができてしまっている。。。

そしていつものstackoverflowから解決策を。

ios - How do I get rid of the -16 when doing horizontal layout to the edge of the superview in Xcode 6? - Stack Overflow

Constraintの指定からRelative to marginのチェックを外す。これが付いているとConstraintの対象が親のVIewの端にならないためなんだそうだ。しかしiOS7と8でUIレンダリング(オートレイアウト周り?)の挙動が違うのは辛いものがあるなあ(T . T)。。。