🧰
【SwiftUI】if節でToolbarを差し替える(ゴリ押し)
Result Builder
SwiftUIのDSLの裏では、ViewBuilderというResult Builderが頑張ってくれている(詳細は省く)。SwiftUIにはViewBuilderだけではなく、SceneBuilder、TableColumnBuilder、ToolbarContentBuilderなど様々なResult Builderが存在する。
ToolbarContentBuilderとif節
buildEitherメソッドを実装していないResult Builderでは、DSL内でif節を使用できない。ToolbarContentBuilderにはbuildEitherメソッドがないので、例えば下のようにEditModeによってツールバーを変化させるようなことができない。
content
.toolbar {
if editMode?.wrappedValue.isEditing ?? false {
editModeToolbar
} else {
defaultToolbar
}
}
しかしToolbarContentBuilderではなくViewBuilderにif文を任せることで、この機能を実現できる。
方法
1.Viewにifモディフィア(メソッド)を生やす
View+If.swift
import SwiftUI
extension View {
@ViewBuilder func `if`<TrueContent: View, FalseContent: View>(
_ condition: Bool,
@ViewBuilder trueContent: (Self) -> TrueContent,
@ViewBuilder else falseContent: (Self) -> FalseContent
) -> some View {
if condition {
trueContent(self)
} else {
falseContent(self)
}
}
}
if condition { ... } else { ... }の部分で、内部的にViewBuilderのbuildEitherを呼び出している。
2.ifモディフィア内でtoolbarをくっつける
@Environment(\.editMode) var editMode
@ToolbarContentBuilder
var defaultToolbar: some ToolbarContent {
ToolbarItem(placement: .navigationBarTrailing) {
...
}
ToolbarItem(placement: .navigationBarTrailing) {
...
}
}
@ToolbarContentBuilder
var editModeToolbar: some ToolbarContent {
...
}
//body内で
content
.if(editMode?.wrappedValue.isEditing ?? false) { view in
view.toolbar { editModeToolbar }
} else: { view in
view.toolbar { defaultToolbar }
}
このような形を取ることで、toolbar(content:)に対して渡す引数は単一のToolbarContentで済むようになり、buildEitherがなくても困ることはない。
参考記事
SwiftLee - How to create a Conditional View Modifier in SwiftUI
Discussion