以前の記事でナビゲーションバーの色を変更可能にしたNavigationViewの実装方法を紹介しました。
上記記事では、カスタムModifierを実装し、以下のようにModifierを指定することでナビゲーションバーの色を変更できるようにしました。
NavigationView { Text("Hello") .navigationBarTitleDisplayMode(.inline) .navigationBarColor(.blue) // ナビゲーションバーの色を青にする }
しかし、ナビゲーションバーの色はブランドカラーとしてアプリ全体で統一することが多く、上記のままだとナビゲーションバーを使う画面それぞれで同じModifierを指定する必要があります。
そこで、共通で使用できるNavigationViewを作成し、それをアプリ全体で使い回すようにします。
共通で使用できるNavigationViewを実装する
ナビゲーションバーの色やタイトルの表示モードなどの設定を含んだ独自のNavigationViewを定義して、以下のように使うことができると良さそうです。
CommonNavigationView { Text("Hello") // ナビゲーションバーの設定をするModifierが必要ない }
このCommonNavigationView
は、以下のように実装します。
struct CommonNavigationView<Content: View>: View { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } var body: some View { NavigationView { content .navigationBarTitleDisplayMode(.inline) .navigationBarColor(.black) } } }
@ViewBuilder
という見慣れないアトリビュートが出てきました。次項で@ViewBuilder
について説明します。
@ViewBuilderとは
@ViewBuilder
はSwiftUIライブラリが提供するResult Builderです。
Result Builderはざっくりいうとクロージャに渡された複数の値を一つにまとめる機能を持っていて(ざっくりすぎ?)、例えばSwiftUIだと以下のようにVStackのクロージャに複数のビューを渡すことで一つのビューを構築しますが、これは@ViewBuilder
が複数のビューをTupleViewという一つの型にまとめてくれているからなんですね。
VStack { Text("Hello") Text("World") }
ViewBuilder
は以下のメソッドを定義しています。上記の例だと戻り値の型がTupleView<(Text, Text)>
になるということですね。
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View
CommonNavigationViewの実装に戻ると、イニシャライザで@ViewBuilder
を適用したクロージャ引数を定義しているので、以下のような実装が可能になるんですね。
CommonNavigationView { Text("Hello") Text("World") }