独自のモディファイアを定義する

下記のような実行画面を作成します。Text ビューを画面にたくさん並べます。

なんの工夫もないコード

ビューをたくさん並べた場合は、それぞれのモディファイアをいちいち書かなければなりません。しかし、プログラマたるもの同じコードを何回も書くのはバカバカしくてやってられません。見栄えを改造したくなった場合、1箇所書き換えたら全部がイッキに書き変わるようにしたいものです。

import SwiftUI

struct ContentView: View {

    var body: some View {

        Spacer()

        Group {

            Text( "MyModifier()" )
                .font( .system( size: 24.0 ) )
                .padding()
                .foregroundColor( .black )
                .background( .yellow )

            Text( "MyModifier()" )
                .font( .system( size: 24.0 ) )
                .padding()
                .foregroundColor( .black )
                .background( .yellow )

            Text( "MyModifier()" )
                .font( .system( size: 24.0 ) )
                .padding()
                .foregroundColor( .black )
                .background( .yellow )

        }

        Spacer()

        Group {

            Text( "MyModifierWithArgs()" )
                    .font( .system( size: 16.0 ) )
                    .padding()
                    .foregroundColor( .white )
                    .background( .red )

            Text( "MyModifierWithArgs()" )
                    .font( .system( size: 24.0 ) )
                    .padding()
                    .foregroundColor( .white )
                    .background( .green )

            Text( "MyModifierWithArgs()" )
                    .font( .system( size: 32.0 ) )
                    .padding()
                    .foregroundColor( .white )
                    .background( .blue )

        }

        Spacer()

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

独自のモディファイアを定義したコード

サンプルソースを見ていただければ、だいたいわかると思いますが、独自のモディファイアを定義するには ViewModifier 型で、そのプロファイルを定義してやります。

上の Group の3つの Text は引数なしの独自のモディファイアを適用しています。

下の Group の3つの Text は、
・文字のサイズ
・前景色(フォント色)
・背景色
を指定する引数を持つ独自のモディファイアを適用しています。

import SwiftUI

struct ContentView: View {

    var body: some View {

        Spacer()

        Group {

            Text( "MyModifier()" )
                .modifier( MyModifier() )

            Text( "MyModifier()" )
                .modifier( MyModifier() )

            Text( "MyModifier()" )
                .modifier( MyModifier() )

        }

        Spacer()

        Group {

            Text( "MyModifierWithArgs()" )
                .modifier( MyModifierWithArgs( font_size: 16.0, color_fg: .white, color_bg: .red ) )

            Text( "MyModifierWithArgs()" )
                .modifier( MyModifierWithArgs( font_size: 24.0, color_fg: .white, color_bg: .green ) )

            Text( "MyModifierWithArgs()" )
                .modifier( MyModifierWithArgs( font_size: 32.0, color_fg: .white, color_bg: .blue ) )

        }

        Spacer()

    }

}

// 引数のない独自のモディファイア.
struct MyModifier: ViewModifier {

    func body( content: Content ) -> some View {

        content
            .font( .system( size: 24.0 ) )
            .padding()
            .foregroundColor( .black )
            .background( .yellow )

    }

}

// 引数のある独自のモディファイア.
struct MyModifierWithArgs: ViewModifier {

    let font_size: CGFloat
    let color_fg: Color
    let color_bg: Color

    func body( content: Content ) -> some View {

        content
            .font( .system( size: font_size ) )
            .padding()
            .foregroundColor( color_fg )
            .background( color_bg )

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

ずいぶん見通しがよくなりました。MyModifier や MyModifierWithArgs の定義を別のファイルに移動すれば管理がラクになって、頭の中がより整理できるように思います。