Slide 1

Slide 1 text

Conditional Content in SwiftUI Potatotips #64 2019/8/27 Yasuharu Yanamura

Slide 2

Slide 2 text

ࣗݾ঺հ • Yasuharu Yanamura/༄ଜ ߁੖ • ɹ@yanamura_ɹɹ@yanamura • ίωώτגࣜձࣾ • ϚϚϦiOSΞϓϦ։ൃ

Slide 3

Slide 3 text

2020/2 potatotips #69 ίωώτͰ։࠵༧ఆʂ

Slide 4

Slide 4 text

+ if / switch

Slide 5

Slide 5 text

৚݅ͰViewΛग़͠෼͚͍ͨ ͱ͍͏ͱ͖͕ͨ·ʹ͋Δ

Slide 6

Slide 6 text

• ͜͏ॻ͘ͱɾɾɾ var body: some View { if imageName.isEmpty { return Text("no image") } else { return Image(imageName) } } ৚݅෼ذͰViewΛग़͠෼͚

Slide 7

Slide 7 text

• ίϯύΠϧΤϥʔʂ var body: some View { if imageName.isEmpty { return Text("no image") } else { return Image(imageName) } } ! Function declares an opaque return type, but the return statements in its body do not have matching underlying types ৚݅෼ذͰViewΛग़͠෼͚

Slide 8

Slide 8 text

var body: some View { if imageName.isEmpty { return Text("no image") } else { return Image(imageName) } } ! Function declares an opaque return type, but the return statements in its body do not have matching underlying types 0QBRVF3FTVMU5ZQF ͳͷͰͭͷܕΛฦ͞ ͳ͍ͱ͇

Slide 9

Slide 9 text

var body: some View { if imageName.isEmpty { return Text("no image") } else { return Text(imageName) } } ಉ͡ܕΛฦ͢ͳΒ0,

Slide 10

Slide 10 text

ղܾํ๏

Slide 11

Slide 11 text

৚݅෼ذΛ࢖͏ํ๏ 1 • Group / HStack / VStack / ZStack var body: some View { Group { if imageName.isEmpty { Text("no image") } else { Image(imageName) } } }

Slide 12

Slide 12 text

৚݅෼ذΛ࢖͏ํ๏ 2 • @ViewBuilder @ViewBuilder var body: some View { if imageName.isEmpty { Text("no image") } else { Image(imageName) } }

Slide 13

Slide 13 text

৚݅෼ذΛ࢖͏ํ๏ 3 • ViewBuilder.buildEither() var body: some View { imageName.isEmpty ? ViewBuilder.buildEither(first: Text("no image")) : ViewBuilder.buildEither(second: Image(imageName)) }

Slide 14

Slide 14 text

ͲΕΛ࢖ͬͯ΋ViewBuilderͷԸܙ

Slide 15

Slide 15 text

ͳͥViewBuilderΛ࢖͏ͱ ղܾ͢Δͷ͔

Slide 16

Slide 16 text

ViewBuilderͷ࢓૊Έ • ViewBuilder͸function builderͰ࣮૷ • function builder͸ίϯύΠϧ࣌ʹifจͷchainͩͬͨΒ buildEither(first:), buildEither(second:)Λ͔ͭ͏

Slide 17

Slide 17 text

ͭ·Γ @ViewBuilder var body: some View { if imageName.isEmpty { Text("Hello") } else { Image(imageName) } } var body: some View { imageName.isEmpty ? ViewBuilder.buildEither(first: Text("no image")) : ViewBuilder.buildEither(second: Image(imageName)) }

Slide 18

Slide 18 text

ViewBuilderͷbuildEither • _ConditionalContentΛฦ͢ extension ViewBuilder { public static func buildEither(first: TrueContent) -> _ConditionalContent where TrueContent : View, FalseContent : View public static func buildEither(second: FalseContent) -> _ConditionalContent where TrueContent : View, FalseContent : View }

Slide 19

Slide 19 text

֬ೝͯ͠ΈΔ @ViewBuilder var body: some View { if imageName.isEmpty { Text("Hello") } else { Image(imageName) } } _ConditionalContent • ໭Γ஋

Slide 20

Slide 20 text

ͳͥViewBuilderΛ࢖͏ͱ ղܾ͢Δͷ͔ ↓ ViewBuilder͕৚݅෼ذΛ _ConditionalContent<,>ʹͯ͠Δ

Slide 21

Slide 21 text

͔͠͠

Slide 22

Slide 22 text

ݱ࣌఺Ͱ͸NGͳέʔε • ❌ switch / if case / if let ... var body: some View { Group { switch foo { case a: Text("a") case b: Text("b") case c: Text("c") } } } ※@ViewBuilderΛ࢖͏ͱίϯύΠϧ͸௨Δ͕ಈ͔ͳ͍

Slide 23

Slide 23 text

ݱ࣌఺Ͱ͸NGͳέʔε • ❌ switch / if case / if let ... var body: some View { Group { switch foo { case a: Text("a") case b: Text("b") case c: Text("c") } } } var body: some View { Group { if foo == .a { Text("a") } else if foo == .b { Text("b") } else if foo == .c { Text("c") } } } • ⭕ if / else if /else

Slide 24

Slide 24 text

Ͳ͏ͯ͠΋if / else Ҏ֎͕࢖͍͍ͨ • AnyViewʹ͢Ε͹ͳΜͱ͔ͳΔ!? var body: some View { switch foo { case .a: return AnyView(Text("a")) case .b: return AnyView(Text("b")) case .c: return AnyView(Text("c")) } }

Slide 25

Slide 25 text

·ͱΊ • ViewBuilderͷྗͰView಺Ͱ৚݅෼ذ͕࢖͑Δ • ͨͩ͠if / else ͷΈ • ࠷ѱAnyViewΛ࢖͑͹if elseҎ֎΋ɾɾ

Slide 26

Slide 26 text

͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠

Slide 27

Slide 27 text

Appendix

Slide 28

Slide 28 text

ifͷΈ

Slide 29

Slide 29 text

ViewBuilderͷ࢓૊Έ • function builder͸ίϯύΠϧ࣌ʹifจ୯ମ(chainͳ͠)ͩͬͨΒ buildIf()Λ͔ͭ͏

Slide 30

Slide 30 text

ͭ·Γ @ViewBuilder var body: some View { if !imageName.isEmpty { Image(imageName) } } var body: some View { ViewBuilder.buildIf( !imageName.isEmpty ? Image(imageName) : nil ) }

Slide 31

Slide 31 text

ViewBuilderͷbuildIf • Content?Λฦ͢ extension ViewBuilder { public static func buildIf(_ content: Content?) -> Content? where Content : View }

Slide 32

Slide 32 text

৚݅෼ذͳ͠

Slide 33

Slide 33 text

ViewBuilderͷ࢓૊Έ • buildBlock()Λ͔ͭ͏

Slide 34

Slide 34 text

ͭ·Γ @ViewBuilder var body: some View { Text("Hello") Image(imageName) } var body: some View { ViewBuilder.buildBlock( Text("Hello"), Image(imageName) ) }

Slide 35

Slide 35 text

ViewBuilderͷbuildBlock • Ҿ਺(ཁૉ)ͷ਺͕ෳ਺ͷ৔߹TupleView<(,...,)>Λฦ͢ extension ViewBuilder { public static func buildBlock(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)> where C0 : View, C1 : View public static func buildBlock(_ c0: C0, _ c1: C1, _ c2: C2, _ c3: C3, _ c4: C4, _ c5: C5, _ c6: C6, _ c7: C7, _ c8: C8, _ c9: C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)> where C0 : View, C1 : View, C2 : View, C3 : View, C4 : View, C5 : View, C6 : View, C7 : View, C8 : View, C9 : View } <<ུ>>

Slide 36

Slide 36 text

֬ೝͯ͠ΈΔ @ViewBuilder var body: some View { Text("Hello") Image(systemName: "circle") } TupleView<(Text, Image)> • ໭Γ஋