【Swift】Xcode9+iOS11でUINavigationBarが正しく表示できなくて困った話

どうも。Reoです。

Xcode9にアップデートしてSwift4デビューもして早10日。

Swift3からSwift4にアップデートは殆ど何事もなくすんなりとアップデートしていて、Swift4の状態で10日くらい作業を進めていました。

そして作業をほとんど終え、後はiOS11にアップデートしてチェックしてから審査だそうというところまで来て、いざiOS11でビルドしてみて驚愕。

 

なんやこの白い隙間は!!!!!

 

 

なんやこのスタンプはwwwwwwwwww

比較すると、Xcode9+iOS11にすると以下のようになってしまいました。

 

 

結論から言うとXcode9のバグらしいです。

スタンプがおかしくなったのはコードを付け足せばすぐに戻すことができたのですが、この高さがおかしいのだけはどうにもならなくてめちゃくちゃ困りました。

 

iOS11になってUINavigationBarがガラッと変わってしまったので、そのせいなんだろうと思って調べていたのでなかなか解決に至りませんでした。

SafeAreaのせいなのだろうなーと思って調べていたのですが、ウーム、どうやら違うぞと。

 

とりあえずやってみたことを書いてみますが、高さに関しては解決しなかったので、私は大人しくxcode8に戻しました。

 

/* ****Xcode9+iOS11でも解決できる方法が見つかりました!(2017/11/11 追記)  **** */

→「iOS11.0でUINavigationBarの高さが正しく表示されない現象について – Qiita」より

UINavigationBarのカスタムクラスを作ってlayoutSubviewsをoverrideする方法です。

通常はリンク先コードそのままでベリーグッドなのですが、自分の場合UINavigationBarをデフォルトの高さで使っていなかったので、UINavigationItemが若干上寄りに配置されてしまいました。

なので以下の部分で調整しました。

    override func layoutSubviews() {
        super.layoutSubviews()
        if #available(iOS 11.0, *) {
            for subview in self.subviews {
                let stringFromClass = NSStringFromClass(subview.classForCoder)
                if stringFromClass.contains("BarBackground") {
                    subview.frame = self.bounds
                } else if stringFromClass.contains("BarContentView") {
                    //ここで位置を調整
                    subview.frame.origin.y = UIApplication.shared.statusBarFrame.height + 10
                    subview.frame.size.height = self.bounds.height - UIApplication.shared.statusBarFrame.height
                }
            }
        }
    }

適当に確認しながら位置調節してください。

 

やっと解決したのが嬉しくてわざわざメールまでしちゃったよ!!

これでようやく私のアプリもX対応する気がおきました。頑張ります。

/* **** ここまで(2017/11/11追記) **** */

PrefersLargeTitlesを設定してみた

iOS11から使える新しいやつなんですが、まずはこいつを設定してみました。

let navigationBar = UINavigationBar()
navigationBar.prefersLargeTitles = true

UINavigationItemの方にも設定をしてみました。

let naviItem = UINavigationItem()
naviItem.largeTitleDisplayMode = .always

 

これ!後々考えるとアホなんですが、LargeTitleを使うよ!っていう設定をしてるんですね。

つまりは、上の画像のようなNavigationBarを採用するよ!ってことですね。

それに気づいてとりあえずfalseにしてみると、また隙間が空いてしまう。デフォルトでfalseが設定されてたので当たり前なんですが。

largeTitleDisplayModeでこいつを常に大きいサイズで表示しているから、それを.neverにしてやればいいんじゃ?と思い、やってみるけれどなーんか上の方に全部寄っちゃうんですよね。全部のItemが気持ち上の方に寄ってるんです。

でも一応このPrefersLargeTitlesをtrueにしてやると高さがおかしいのは直るんですね。中身は上よりですが。

 

解決?

そしてたどり着いたのがここ。

How to change navigationBar height in iOS 11? – stackoverflow

みんな大好きstackoverflowなんですが、ここにXcode9のバグだぞって書いてあるんですね。

そんなバグありかよーって感じなんですが、バグだとわかってもどうにかするっきゃない。せっかくアップデート版のリリースまであとそれだけなのに、そんな修正待ってられない・・・。

 

んで、NavigationBarの高さがおかしいっていう記事も結構調べたんですが、一応背景色つけたら高さはとれてるし、やっぱり私の場合はバグのせいでおかしくなっているんだと結論づけました。

そもそもUINavigationControllerでのUINavigationBarなら大丈夫っぽくて(試してないのですが)、私のように単独で使ってる人とそうでない人の場合でも状況は異なると思うんですね。

調べて高さがどうにかなるコードをいくつもみましたが、それを自分のに当てはめてもどうもうまくいかないってときは、もしかすると私と同じようにXcode9のバグのせいかもしれないです。

 

UINavigationBarに設定するrightBarItem等のサイズがおかしくなる件

ついでに、スタンプがおかしくなっている方は普通に解決できまして、

UINavigationBarのItemとしてUIViewを用いて設定する時に、

le imageView = UIImageView()  
let widthConstraint = imageView.widthAnchor.constraint(equalToConstant: 32)
let heightConstraint = imageView.heightAnchor.constraint(equalToConstant: 32)
heightConstraint.isActive = true
widthConstraint.isActive = true

と書いてやれば、おkです。

navigation bar rightbaritem image-button bug iOS 11 – stackoverflow

こちらで解決しました!

 

Xcode8へ戻す・・・

結局のところ、私はXcode8に戻すという方法をとったのですが、これがまた厄介なことになって意外と時間食われてしまいました。

まず、もしかしたらXcode9.1 betaにすれば治ってるんじゃ?と思った私は(無駄に)OSごとアップデート。HighSierra betaの人柱になってきました。結局Slackが動かなくなったので普通にbetaじゃない方に戻ったんですけどねw

Xcode9.1 betaなら戻ってるんじゃ?っていうのは失敗で、結局そっちに変えても何も変わりませんでした。残念。

 

そいで次にXcode8をダウンロードし直すことに。

Apple DeveloperでログインしてDownloadでXcode8.3.2を探してきてダウンロード。

(xipファイルで躓いたのは「xipファイルの解凍時に「データが壊れています」と出て解凍できなかった話」を参照。つらい。)

 

Xcode8に戻して気づく。あれ、Xcode8ってiOS11動かせるんだっけ?

これはYESでXcode8でもiOS11は動かせました。ちょっと面倒ですが、こちら(Using iOS 11 devices with Xcode 8.2.1 – stackoverflow)の通りにiOS11のディスクイメージをXcode8の方にいれてやればおkです。

そしていざチェックをしてみようとビルドボタンを押すと、Swiftのバージョンが違うよって言われてしまいました。あれ?Xcode8ってSwift4動かせるの?ってことにやっとここで気づく・・・。

Is it possible to compile Swift 4 on Xcode 8.x? – stackoverflow」ではYESと書いてあり、こちらに書かれている通りにやってみたんですが、どうもうまくいかない。。。。SDKがなんやらというエラーが出ました。

 

色々彷徨った結果、もうこれSwift3の状態に戻す方が早いじゃんと思い、Swift4からSwift3に戻す作業をしました。

そしてビルド!隙間できない!

ということで、Xcode8.3.2+Swift3+iOS11の環境ではナビゲーションバーは今まで通り表示することができました。

っていうか現在リリースされている状態のアプリをiOS11の環境で動かしてて大丈夫なんだから、そりゃ大丈夫だよねって感じでもあります。

 

でも結局Xcode9のせいなのかSwift4のせいなのかはわからないですねー。

Swift3に戻したので当たり前ですけど、PrefersLargeTitlesとかは使えないです。

まぁでもSwift4の状態でiOS10では大丈夫だったんだから、やっぱりXcode9+iOS11だからダメなのかなー。わからない。

とにかく、もうしばらく私のアプリはこの環境でやっていくのが良さそうです。

 

どうでもいいけど、Robinちゃんには全然ライブラリいれてないので(広告のやつだけ)、Swift3からSwift4への移行もすぐだったんですけど、ライブラリいれてるとなかなか面倒ですね・・・。

でもなんだろう、フレームワークに振り回されている感があってウ〜〜ンと思ってはいます。

早く修正されて欲しい限りですが、もうUINavigationBarとか使うのが良くないんじゃねとかも思っちゃって、フレームワークを信じすぎるのもなんだか結局用意されたものを組み立てているだけみたいな感じでなんともいえない気分です。

 

とりあえずはもうしばらくこのXcode9とSwift4に振り回されそうだなーって感じ。

ではではこの辺で。

 

追記(同日):別アプリをSwift3→Swift4にする過程で、iOS11+Swift3+Xcode9で動かしてみたところ、UINavigationBarはバグっていました。やっぱりXcode9のバグで間違い無いっぽいですね。

 

2018/04/14追記 UINavigationControllerに移行するのが一番確実
【Swift4】UINavigationControllerのNavigationBarをカスタマイズしてみた。【高さ変更】にUINavitaionControllerでのNavigationBarのカスタマイズ方法について書きましたのでそちらを参照してください!

ほんっっっっとうに、UINavigationControllerに移行するのが一番楽です。

自分UINavigationControllerが苦手でずっとUINavigationBar単体でしか使ってこなかったんですが、今回の件で全てUINavigationControllerに移行しました。

それほどまでにUINavigationBar単体とiPhoneXの相性が悪いです。
いっそのことUINavigationBar単体にも自動でsafeAreaついてくれたらいいのにってめちゃくちゃ思います。

Comments...

コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS
more