うるおいらんど

アプリ開発やサイト制作のメモとか。

【Swift4】UINavigationControllerのNavigationBarをカスタマイズしてみた。【高さ変更】

魚ライン
魚ライン

どうも。Reoです。Swift記事はお久しぶりですね。

今回は、UINavigationController内のナビゲーションバーをカスタマイズしてみました。

 

ずっとUINavigationBarを単独で使っていたのですが、iPhoneXが出て、単独だとセーフエリアを考慮するのがとても面倒なことを実感しました。なので最近はUINavigationControllerを使う方向に移行しています。

以前「【Swift】Xcode9+iOS11でUINavigationBarが正しく表示できなくて困った話」という記事を書いたのですが、これも結局iPhoneX対応ではなく、高さをちゃんと表示するための対応策でしかないんですよね。

これだと結局UINavigationBarを単独で使うときは、iPhoneXかどうかの場合分けを書く必要が出てしまっていました。

この問題の一番簡単な解決策は、「ちゃんとUINavigationControllerを使おう!」なんですよね。

ただし、上記リンクの記事でお話しした「Xcode9での高さが反映されないバグ」は(おそらく)今回も発生していました。

 

今までUINavigationControllerをまともに使ってきたことがない最大の理由は、ナビゲーションバーのカスタマイズがわからない!ってことでした。ツールバーも同様です。

今回はUINavigationController内の

・ナビゲーションバーの色を変更
・ナビゲーションバーの高さを変更

をメインに実装していこうと思います。

StoryBoardは使いません!

コード見りゃわかるって人はこちらからどうぞ。uruly/CustomNavigationController-CustomNavigationBar

 

UINavigationControllerを継承したクラスを用意しよう

まずはUINavigationControllerを継承したクラスを作ります。

File > New > File より Cocoa Touch Class を選択。 Subclass of をUINavigationControllerにして作成



 

rootViewControllerの設定と、ナビゲーションバーとツールバーのクラスの設定をまとめてしたかったので、簡易イニシャライザを用意します。ここは別に飛ばしてもk。

作ったクラス内(CustomNavigationController)にinit文を書いていきます。

ここは丸っとコピペでおk。

init(nibName:bundle:)のoverrideを書かなかったらエラーが出ました。


Fatal error: Use of unimplemented initializer ‘init(nibName:bundle:)’ for プロジェクト名.CustomNavigationViewController
 

簡易イニシャライザを作成。

先ほど書いたinit(navigationBarClass:,toolbarClass)を使います。

一応init(rootViewController:)の部分は書かなくてもなんの問題もありません。

ただし、書いてないとinit(rootViewController:)での初期化ができなくなるので、ナビゲーションバーやツールバーをカスタムしないで使おうというときでも呼び出すことができません。

 

ここまでのまとめ

 

初期表示画面にNavigationViewControllerを用いよう

先ほど作ったのをとりあえず初期表示させたいのでAppDelegate.swift内に以下のように書きます。

 

簡易イニシャライザを作ってないときは

としてあげればおkです。

ここまでで実行すれば、ナビゲーションバーがついたViewが表示されるはずです。

 

カスタムナビゲーションバーを作ろう

カスタムナビゲーションバーを作ります。

File > New > File より Cocoa Touch Class を選択。 Subclass of をUINavigationBarにして作成



この中にイニシャライザを書きます。

 

先ほどのCustomNavigationViewControllerを生成するところで、このCustomNavigationBarを使うように設定しましょう!

簡易イニシャライザを用意してない人は

とします。

 

これでカスタマイズの準備はおk!

 

ナビゲーションバーの色を変えてみよう

まずは簡単にナビゲーションバーの色を変えてみましょう。

先ほどのCustomNavigationBarクラス内に

ハイライトしたところを付け足しました。

 

これで実行してみるとバーの色が変わったのがわかると思います。

 

rootViewController上での設定

ナビゲーションバーにタイトルをつけましょう。

タイトルはNavigationControllerのrootViewControllerに設定されているViewControllerにて設定します。
今回の場合だとlet vc = ViewController()としたこいつです。

ViewController内でタイトルを書きましょう。

 

ここまでを実行するとこうなりました。



このViewController内でキャンセルボタンを設置してみましょう。

ここに最初はめちゃくちゃハマりました。

 

これだけ見るとどこにハマる要素があるの?って思うかもしれないですが、例えばナビゲーションバーを隠したいときは以下のように書きます。

バーの色を変えたいときは

うんうん、じゃあバーアイテムを置くときは

ってナンデヤネンヽ(#゚Д゚)ノ┌┛)`Д゚)・;’

 

ということで、バーアイテムを置くときはself.navigationItemに設定しないと反映されません。私のようにハマらないように気をつけてくださいね。

 

ナビゲーションバーの高さを変更しよう

今回一番やりたかったことはコレです。

CustomNavigationBar内でsizeThatFitsをoverrideします。

本来ならコレだけでバー自体の高さは決まるのでは?と思っているのですが、どうにも変化がない。

ここの部分が一番最初に話した「Xcode9+ios11でのバグ」なんじゃないかなーと思ってます。

ここまでの状態でiOS9とiOS10で検証してみたところ、指定した高さにちゃんとなりました。



わかりやすいようにaddHeightを100にしてあります。

iOS11だと高さはデフォルトのまま表示されてしまいます。

 

ということで「【Swift】Xcode9+iOS11でUINavigationBarが正しく表示できなくて困った話」で用いた方法でiOS11に対応していきます。

CustomNavigationBarのlayoutSubviewsをoverrideします。

書いている時に気付いたので修正したのですが、

のoriginがself.bounds.originだとステータスバー分隙間が空いてしまいます。

とりあえずその分だけマイナスしたところから表示するようにしました。

ステータスバーを表示しない設定の場合はself.bounds.originでおkです。(x:0,y:0)

ここまで動かすとiOS11のiPhone7だとちゃんと高さが反映されました。やったね。

 

と思ってiPhoneXで動かすと反映されてないことに気づきました。記事書くの一時中断して戦ってました。無事なんとかなりましたのでので。

 

iPhoneXに対応する!

上記コードで動かしてもiPhoneXでは高さが反映されません。というか、反映はされているんですが何か高さ足りてないんです。

そう!足りないのはsafeArea部分!

高さを変えなければ自動で考慮してくれるのですが、高さを変更してしまうとそこを自分で設定しないといけません。

CustomNavigationBar内のsizeThatFitsに以下のように書き足します。

 

これでiPhoneXでも高さを変更することができました。



左からiOS10,iOS11,iPhoneXです。

あと少し気になるところがありますね。ナビゲーションバーの要素の高さです。

今回はiOS10での表示に合わせます。

先ほどのlayoutSubviewsのところに付け加えます。

付け加えた高さ分で大体iOS10での表示と同じになります。

 

CustomNavigationBarの全文コードはこうなりました。

 

これでおkのはず!決め打ちしていた高さを定数にしておいたよ。

以上です!!!!!!!

 

ついでにブログを書くのと同時に作ったサンプルをgithubにあげました。

uruly/CustomNavigationController-CustomNavigationBar

記事の通りのことしかしてないですが、もしかするとカスタムツールバーを付け加える可能性も。そのときはまた記事書くかもしれないですけどね〜。

 

結局iPhoneXでの場合分け書いてるじゃんね・・・

iPhoneXにも関わらずsafeAreaInsets.topが0ならば、CustomNavigationControllerで

としてみるとうまくいくかもしれない。

今回はなくてもちゃんとsafeAreaInsets取れたので、書いてないですが、もし0の場合は設定される前に呼ばれてるかもしれませぬ。

 

以上でっす。何かの役に立てば〜。

ではでは。

 

追記(2018/02/03)

ステータスバーを表示しないときに、iPhoneXだとナビゲーションバーの上に空白ができてしまいます。

そんなときはsafeAreaInsets.top分をマイナスしてあげてください。

githubの方にあげたやつも修正しました!

魚ライン
モッピー!お金がたまるポイントサイト
魚ライン

Swiftの記事一覧を見る

コメント

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

コメントを残す

コメント時の注意

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

魚ライン 魚ライン