(2020/05/4 更新)
SwiftUIでは、定形のModifierをまとめたカスタムModifierを作成できます。これは、繰り返し処理を避け、ソースの簡素化をはかるのに有効です。
本記事では、カスタムModifierの定義方法と使用方法を紹介します。
環境
この記事の情報は次のバージョンで動作確認しています。
【Xcode】11.4.1
【Swift】5.2
【iOS】13.4.1
【macOS】Catalina バージョン 10.15.4
【Swift】5.2
【iOS】13.4.1
【macOS】Catalina バージョン 10.15.4
カスタムModifierの定義
カスタムModifierはViewModifier protocolに準じた構造体として定義します。
次のコードはタイトル用のカスタムModifier”MyTitle”を定義するサンプルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// カスタムModifier(MyTitle)の定義 struct MyTitle: ViewModifier { let color: Color func body(content: Content) -> some View { content .font(.largeTitle) .foregroundColor(.white) .padding() .background(color) .clipShape(RoundedRectangle(cornerRadius: 10)) } } |
使用する際には次のようにmodifier()メソッドを使います。
1 2 3 4 5 6 7 8 |
struct ContentView: View { var body: some View { Text("カピ通信") .modifier(MyTitle(color: .blue)) // カスタムModifierの使用 } } |
注意点として、カスタムModifier内で使えるのは、View protocol に準拠している標準Modifierのみです。
例えば fontWeight() のように、特定のViewにしか有効でないものは使えません。
標準Modifier以外のメソッドも含める場合は、こちらの方法を使います。
modifier()メソッドをラップする
次のようにViewのextensionとして定義する事で、modifier()メソッドを任意のメソッドに置き換えられます。
1 2 3 4 5 6 7 8 |
// カスタムModifierのメソッド名を titleStyle() に置き換え extension View { func titleStyle(color: Color) -> some View { self.modifier(MyTitle(color: color)) } } |
先程のmodifier()メソッドを呼び出す部分が次のように置き換えられます。
1 2 3 4 5 6 7 8 |
struct ContentView: View { var body: some View { Text("カピ通信") .titleStyle(color: .blue) // カスタムModifierの使用 } } |
カスタムModifierでView構造を定義する
カスタム修飾子は、既存の修飾子の組み合わせだけでなく、必要に応じて新しいView構造を作成できます。
次の例は、ViewをStackに埋め込み、別のViewを追加するオブジェクトを作成する事で、著作権表示の機能を実現しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// 著作権表示を付加するカスタムModifierの定義 struct Watermark: ViewModifier { var text: String func body(content: Content) -> some View { ZStack(alignment: .bottomTrailing) { content Text(text) .font(.callout) .foregroundColor(.white) .padding(5) .background(Color.black) } } } // カスタムModifierのメソッド名を watermarked() に置き換え extension View { func watermarked(text: String) -> some View { self.modifier(Watermark(text: text)) } } struct ContentView: View { var body: some View { Image("capibara") .resizable() .scaledToFill() .frame(width: 300, height: 200) .clipped() .watermarked(text: "カピ通信") // カスタムModifierの指定 } } |
標準Modifier以外のメソッドを含める場合
前章までで示した方法では、標準Modifier以外のメソッドが使えません。
標準Modifier以外のメソッドを含めたい場合は、次のようにextensionで拡張する方法が使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct ContentView: View { var body: some View { Text("カピ通信") .titleStyle(color: .blue) } } extension Text { func titleStyle(color: Color) -> some View { self .font(.largeTitle) .fontWeight(.black) // 標準Modifierでないメソッド .foregroundColor(.white) .padding() .background(color) .clipShape(RoundedRectangle(cornerRadius: 10)) } } |
あわせて読みたい記事
【SwiftUI】Modifierの適用順
Viewに様々な変更を適用するModifierですが、適用する順番によって挙動が変わる事があります。 これはModifierが既存のViewのプロパティを変更しているのでは無く、変更を適用した新しいViewを毎回作成している事に関係します。
【SwiftUI】Modifierをまとめて適用する
コンテナで括られた複数のViewに対して、Modifierをまとめて適用する方法を紹介します。