この投稿は何?
SwiftUIフレームワークを使ったアプリ開発では、いくつものビューを組み合わせて画面を構築していきます。そのビューの外観や振る舞いを設定するために使用するのがビューモディファイアです。
ここでは、独自のビューモディファイアを定義して呼び出す方法について、実践・解説します。
実行環境
macOS 11.4
Xcode 12.5.1
Swift 5.4
ハンズオン
作成するモディファイアは、「ビューにチェックマークをつける」というものです。
ViewModifierプロトコル
新しいファイルを作成して、そこにMark
という名前の構造体を定義します。
import SwiftUI
struct Mark: ViewModifier {
func body(content: Content) -> some View {
// ビューを返す
}
}
「モディファイアとして呼び出せるメソッド」を実装するには、その型をViewModifier
プロトコルに適合させる必要があります。ViewModifier
プロトコルは、型にbody(_:)メソッドの実装を要求します。
このメソッドが受け取る’content’パラメータは、モディファイアの適用対象となるビューを示します。そして、返り値の型として宣言されているsome View
が、モディファイア適用後のビューです。
body(_:)メソッド
ここでは、適用対象となるビューの左側に「緑色のチェックマーク」を配置します。ビュービルダー形式でコードを記述することができます。
struct Mark: ViewModifier {
func body(content: Content) -> some View {
HStack {
Image(systemName: "checkmark.circle")
.foregroundColor(.green)
content
}
}
}
以上で、独自のモディファイアを定義することができました。
モディファイアを呼び出す
作成したモディファイアを適用するには、ビューのmodifier(_:)
メソッドを呼び出します。
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.modifier(Mark())
}
}
プレビューでは、テキストの左側に「緑色のチェックマーク」が配置されます。
ただし、このコードは「一般的なビューモディファイア」とは呼び出し方が異なっていることがわかります。
.marked()
のように、「モディファイアらしい方法」で呼び出したいところです。
モディファイアらしい呼び出し方
View
型を拡張して、モディファイアの望ましい呼び出し方法を実装します。
struct Mark: ViewModifier {
func body(content: Content) -> some View {...}
}
extension View {
func marked() -> some View {
return self.modifier(Mark())
}
}
理想的なメソッド名を宣言して、some View
型を返すようにします。メソッドのボディでは、自身のインスタンスに対して「元のモディファイアメソッド」を適用したビューを返すでけです。
これで、モディファイアはよりSwiftUIっぽい形式で呼び出せるようになります。
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.marked()
}
}
パラメータを受け取るモディファイア
マークの種類を変更するために、モディファイアがパラメータを受け取ることもできます。
struct Mark: ViewModifier {
var isChecked: Bool
func body(content: Content) -> some View {
HStack {
if isChecked {
Image(systemName: "checkmark.circle")
.foregroundColor(.green)
} else {
Image(systemName: "xmark.circle")
.foregroundColor(.red)
}
content
}
}
}
extension View {
func mark(isChecked: Bool) -> some View {
return self.modifier(Mark(isChecked: isChecked))
}
}
ここでは、「緑のチェック」か「赤のバツ」のいずれかをマークするようにモディファイアを定義しました。
呼び出し側のコードでは、モディファイアにBool
値を指定します。
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.mark(isChecked: false)
}
}