🧰
【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文を任せることで、この機能を実現できる。
方法
View
にif
モディフィア(メソッド)を生やす
1.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
を呼び出している。
if
モディフィア内でtoolbarをくっつける
2.@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