Skip to content

Instantly share code, notes, and snippets.

@kntkymt
Last active October 27, 2023 06:57
Show Gist options
  • Save kntkymt/ac138a46cd6d409e86aa738637393319 to your computer and use it in GitHub Desktop.
Save kntkymt/ac138a46cd6d409e86aa738637393319 to your computer and use it in GitHub Desktop.
ViewBuilderとifあれこれ
import SwiftUI
struct CounterView: View {
@State var counter = 0
var body: some View {
Button {
counter += 1
} label: {
Text(counter.description)
}
}
}
struct IfViewBuilderTest: View {
@State var condition = true
var body: some View {
VStack {
someView()
Button {
condition.toggle()
} label: {
Text("toggle")
}
}
}
// ViewBuilderをつけるのとつけないので挙動が変わる
// つける->分岐が別々のIdentityになるので分岐によって状態が消える
// つけない->分岐が同じIdentityになるので分岐によって状態が消えない
// ただし、ViewBuilderをつけないということは分岐の左右の型が一致している必要があるので
// ViewBuilderをつけなくて良いケースは三項演算子で代替可能である
// @ViewBuilder
func someView() -> some View {
if condition {
CounterView()
.foregroundStyle(.blue)
} else {
CounterView()
.foregroundStyle(.red)
}
}
}
struct IfViewBuilderTestAnyView: View {
@State var condition = true
var body: some View {
VStack {
someView()
Button {
condition.toggle()
} label: {
Text("toggle")
}
}
}
// AnyViewを使ってViewBuilderを回避できるが
// 状態が消えてしまうため各分岐のIdentityが別であると認識されている
// AnyViewは表面上の型情報を消しているだけでIdentity的な影響はないと考えられる
func someView() -> some View {
if condition {
AnyView(CounterView()
.foregroundStyle(.blue)
.background(Color.yellow))
} else {
AnyView(CounterView()
.foregroundStyle(.red))
}
}
}
struct IfViewBuilderTestIfExtension: View {
@State var condition = true
var body: some View {
VStack {
someView()
Button {
condition.toggle()
} label: {
Text("toggle")
}
}
}
// ViewBuilderを使ってないifのextensionなら実はIdentityを変えずに使える
// 正し、各分岐の型が一致している必要があるので
// trueとfalseで別々のmodifierを使うことはできない
func someView() -> some View {
CounterView()
.if(condition) { view in
view.foregroundStyle(.blue)
} else: { view in
view.foregroundStyle(.red)
}
}
}
extension View {
func `if`<Content: View>(
_ condition: Bool,
_ then: (Self) -> Content,
`else`: (Self) -> Content
) -> some View {
if condition {
then(self)
} else {
`else`(self)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment