Slide 1

Slide 1 text

SwiftUIͰUIViewΛ࢖͏ͱ͖ͷ ϨΠΞ΢τॲཧ Apurin Mikhail @ YUMEMI.swift #14

Slide 2

Slide 2 text

ࣗݾ঺հ Apurin Mikhail ΞϓϦϯɾϛϋΠϧ auramagi apurin.me 􀒡 - ΏΊΈͷiOSΤϯδχΞ - ࠓݱࡏϩγΞ͔ΒϦϞʔτϫʔΫ - ژ౎ → ϞεΫϫͷఱؾΪϟοϓ͸͙͍͑ (+13° → -17°) - ିग़ͷM1 Max MacBook Proಧ͘௚લʹߦͬͨͷ͕੯͍͠

Slide 3

Slide 3 text

ࠓ೥ͷৼΓฦΓ ͳΜͱͳ͘SwiftUIΛ৮Δػձ͕ଟ͔ͬͨҰ೥ͩͬͨ - UIKitͷҊ݅ͰϓϨϏϡʔΛಋೖ - iOS 13.0·ͰҾ্͖͛Δ४උ - σϞΞϓϦ౳ͷ࡞੒ - ΏΊΈࣾ಺ͷSwiftUIษڧձ։࠵ - ݸਓ։ൃ 🥰

Slide 4

Slide 4 text

SwiftUIͰUIKitͷϏϡʔ͕࢖͍͍ͨ - εΫϥονͷҊ݅Ͱ͸ͳ͍ͳΒɺ஥ྑ͘ڞଘ͢Δඞཁ͕͋Δ - Apple͕४උ͞Ε͍ͯΔ΋ͷΛ࢖͑͹Ͱ͖Δ - UIView → UIViewRepresentable - UIViewController → UIViewControllerRepresentable

Slide 5

Slide 5 text

struct LabelRepresentable: UIViewRepresentable { let text: String func makeUIView(context: Context) -> UILabel { .init() } func updateUIView(_ uiView: UILabel, context: Context) { uiView.numberOfLines = 0 uiView.text = text } } UIViewRepresentableΛॻ͍ͯΈΔ ؆୯ʹॻ͚·͢ʂ ඞਢϝιου: - Ϗϡʔੜ੒ makeUIView - Ϗϡʔߋ৽ updateUIView

Slide 6

Slide 6 text

struct LabelRepresentable_Previews: PreviewProvider { static var previews: some View { LabelRepresentable( text: "Journey before destination" ) } } ΍ͬͨʂ ɻɻɻ Μʁ தԝἧ͑ʹͳ͍ͬͯͳ͍ʂʂ PreviewͰ࢖ͬͯΈΔ

Slide 7

Slide 7 text

struct LabelRepresentable_Previews: PreviewProvider { static var previews: some View { LabelRepresentable( text: "Journey before destination" ) .border(.red) .padding() } } ը໘શମͷαΠζΛऔ͍ͬͯΔ SwiftUI ͷ Text ͷΑ͏ʹɺͽͬͨΓͷαΠζΛͱͬͯ
 தԝἧ͑ʹͳΔΠϝʔδ͕ͩͬͨɺ·͍͍͔͋ʁ PreviewͰ࢖ͬͯΈΔ

Slide 8

Slide 8 text

struct LabelRepresentable_Previews: PreviewProvider { static var previews: some View { LabelRepresentable( text: "To love the journey is to accept no such 
 end. I have found, through painful experience, 
 that the most important step a person can take 
 is always the next one." ) .border(.red) .padding() } } PreviewͰ࢖ͬͯΈΔ Ξ ͩΊͩʔ orz

Slide 9

Slide 9 text

SwiftUIͷϨΠΞ΢τॲཧ WWDC 2019 — Building Custom Views with SwiftUI ͦ΋ͦ΋SwiftUIͰͲ͏΍ͬͯҐஔͱαΠζ͕
 ܾΊΒΕΔͷ͔ʁ ϨΠΞ΢τॲཧͷৄࡉ͸ඇެ։ͳͷͰ
 υΩϡϝϯτ͕΄΅ͳ͍ 😔 جຊͷॲཧ͸ҎԼͷεςοϓ͔ΒͳΔ 1. ਌View͕ࢠViewʹαΠζΛఏҊ͢Δ 2. ࢠView͕ࣗ෼ͷαΠζΛܾΊΔ 3. ਌View͕ࣗ෼ͷ࠲ඪۭؒͰࢠViewΛ഑ஔ͢Δ

Slide 10

Slide 10 text

SwiftUIͷϨΠΞ΢τॲཧ ViewͷαΠζ͸࣍ͷܗʹͳ͍ͬͯΔͱਪଌͰ͖Δ struct Dimension { let min: CGFloat let ideal: CGFloat let max: CGFloat } - min: ࠷௿஋ - ideal: ཧ૝αΠζ - max: ࠷ߴ஋ - ؔ܎Λݫक: min <= ideal <= max

Slide 11

Slide 11 text

SwiftUIͷϨΠΞ΢τॲཧ ఏҊαΠζ͸࣍ͷܗͰ౉͞ΕΔͱਪଌͰ͖Δ struct ProposedSize { let width: CGFloat? let height: CGFloat? } - ஋͕ࢦఆ͞Ε͍ͯΔ৔߹͸ɺͦΕΛϕʔεʹαΠζΛܭࢉ - nilͷ৔߹͸ɺViewࣗ਎ͷidealαΠζΛͱΔ - . fi xedSizeͰnilʹมߋ͞ΕΔ

Slide 12

Slide 12 text

SwiftUIͷϨΠΞ΢τॲཧ ௨ৗͷ৔߹͸ɺҎԼͷܭࢉ͕ࣜదԠ͞ΕΔ if let proposedWidth = proposedSize.width { // dimensionsͰ্ݶ஋ɾԼݶ஋Λ཈͑Δ width = max( dimensions.min, min(dimensions.max, proposedWidth) ) } else { width = dimensions.ideal } // height΋ಉ༷

Slide 13

Slide 13 text

Color.mint .frame( minWidth: 100, maxWidth: 200, minHeight: 100, maxHeight: 200 ) .frame(width: 300, height: 300) .border(.mint) SwiftUIͷϨΠΞ΢τॲཧ 📱 W: 390 H: 763 .frame(minWidth: 200, …) .frame(width: 300, height: 300) Color ఏҊαΠζ ࣮αΠζ W: 300 H: 300 W: 200 H: 200 W: 300 H: 300 W: 200 H: 200 W: 200 H: 200

Slide 14

Slide 14 text

Text("Hello YUMEMI.swift") .fixedSize() .border(.mint) .frame(width: 300, height: 300) .border(.mint) SwiftUIͷϨΠΞ΢τॲཧ 📱 W: 390 H: 763 .fixedSize() .frame(width: 300, height: 300) Text("Hello YUMEMI.swift") ఏҊαΠζ ࣮αΠζ W: 300 H: 300 W: nil H: nil W: 300 H: 300 W: 149.7 H: 20.3 W: 149.7 H: 20.3

Slide 15

Slide 15 text

UIKitͱͷޓ׵ੑ Ͱ͸ɺͦͷॲཧͰͲ͏΍ͬͯUIViewͷαΠζ͕ܾΊΒΕΔʁ • SwiftUIଆͷϥούʔ͕Α͠ͳʹ΍ͬͯ͘ΕΔʢʣ • UIViewRepresentable • UIViewControllerRepresentable • ͦΕͧΕͷڍಈ͕ҧ͏

Slide 16

Slide 16 text

UIViewRepresentable AutoLayoutͷintrinsicαΠζͱpriorityΛݩʹͯ͠αΠζΛܭࢉ Intrinsic size Compression Resistance Hugging ݁Ռ
 (min … ideal … max) (-1) - - 0 … 0 … ∞ x < 750 < 750 0 … x … ∞ x < 750 >= 750 0 … x … x x < 750 < 750 x … x … ∞ x >= 750 >= 750 x … x … x -1 = UIView.noIntrinsicMetric 750 = UILayoutPriority.defaultHigh

Slide 17

Slide 17 text

UIViewRepresentable 1. AutoLayoutͷϓϩύςΟ͔ΒUIView͕औΕΔαΠζΛܾఆ 2. ී௨ͷܭࢉࣜͰɺఏҊ͞ΕͨαΠζ͔Β࣮αΠζΛܭࢉ 3. UIViewͷ invalidateIntrinsicContentSize() ͕ݺ͹ΕͨΒ΍Γ௚͠

Slide 18

Slide 18 text

UIViewRepresentable 1 ͱ 2 ͷڍಈ͸ௐ੔Ͱ͖Δඇެ։API͕͋Δ ⚠ ඇެ։APIͳͷͰϦϦʔεϏϧυʹೖΕͪΌμϝ ⚠ public protocol UIViewRepresentable { // 1 (AutoLayoutϓϩύςΟ → ͳΕΔαΠζ) func _overrideLayoutTraits( _ layoutTraits: inout SwiftUI._LayoutTraits, for uiView: Self.UIViewType ) // 2 (ఏҊαΠζ → ࣮αΠζ) func _overrideSizeThatFits( _ size: inout CoreGraphics.CGSize, in proposedSize: SwiftUI._ProposedSize, uiView: Self.UIViewType ) }

Slide 19

Slide 19 text

UIViewControllerRepresentable UIViewRepresentableͱൺ΂ͯɺௐ੔Ͱ͖Δ͜ͱ͕গͳ͍ • preferredContentSize ͰidealαΠζΛࢦఆՄೳ • ҎԼͷViewαΠζ͕ܾఆ͞ΕΔ • 0 … preferredContentSize … ∞

Slide 20

Slide 20 text

import RepresentableKit struct UILabel_Previews: PreviewProvider { static var previews: some View { UIViewAdaptor { let view = UILabel() view.numberOfLines = 0 view.text = "To love the journey is to accept no 
 such end. I have found, through painful experience, that the most important step a person can take is always the next one." return view } .padding() } } RepresentableKitͷ঺հ UIViewRepresentableͷαΠζܭࢉΛந৅Խͯ͠
 ΑΓ؆୯ʹ࢖͑ΔΑ͏ʹϔϧύʔϥΠϒϥϦΛ
 ࡞Γ·ͨ͠ɻ
 https://github.com/yumemi-inc/RepresentableKit

Slide 21

Slide 21 text

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