Slide 1

Slide 1 text

4XJGU6*Ͱ ೋॏεΫϩʔϧ࡞ͬͯΈͨ f o r Ϟ ό ν Ω ʙ .PC JMF 5J Q T ڞ ༗ ձ ʙ

Slide 2

Slide 2 text

} var employedBy = "YUMEMI Inc." var job = "iOS Tech Lead" var favoriteLanguage = "Swift" var twitter = "@lovee" var qiita = "lovee" var github = "el-hoshino" var additionalInfo = """ ٱʑͷొஃ͗ͯ͢Կ΋͔΋๨ΕͯΔʂ """ final class Me: Developable, Talkable {

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN εΫϩʔϧͷॳظҐஔΛ ը૾ͷԼʹ

Slide 5

Slide 5 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN εΫϩʔϧͯ͠΋ ը૾ͷҐஔ͸มΘΒͳ͍ ԼʹεΫϩʔϧʹͭΕͯ എܠͷෆಁ໌౓্͕͕Δ

Slide 6

Slide 6 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN ԼʹΦʔόʔεΫϩʔϧ͚ͨ࣌ͩ͠ ը૾΋ҰॹʹԼ͕Γ·͢ ϦϑϨογϡϓϩάϨε΋ දࣔ͠·͢

Slide 7

Slide 7 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN എܠࣗମ͸ৗʹෆಈ

Slide 8

Slide 8 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN 0, ϋ΢εϘλϯ͕λοϓ͞Ε·ͨ͠ ࣮͸ͨͩͷը૾Ͱ͸ͳ͘ ϘλϯͰͨ͠ʂ

Slide 9

Slide 9 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN എܠ ϝΠϯϘλϯ εΫϩʔϧϏϡʔ

Slide 10

Slide 10 text

struct BackgroundView: View { var body: some View { LinearGradient( colors: [ .mint.opacity(0.5), .cyan, ], startPoint: .top, endPoint: .center ) .ignoresSafeArea() } }

Slide 11

Slide 11 text

struct PrimaryView: View { var body: some View { VStack { Button { } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } } .frame(maxHeight: .infinity, alignment: .top) } }

Slide 12

Slide 12 text

struct PrimaryView: View { @State private var showsDialog = false var body: some View { VStack { Button { showsDialog = true } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } } .frame(maxHeight: .infinity, alignment: .top) .confirmationDialog("Message", isPresented: $showsDialog, actions: { Text("OK") }, message: { Text("ϋ΢εϘλϯ͕λοϓ͞Ε·ͨ͠") }) } } 0, ϋ΢εϘλϯ͕λοϓ͞Ε·ͨ͠

Slide 13

Slide 13 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) } .background(Color.black.opacity(0.8)) } }

Slide 14

Slide 14 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { var topPadding: CGFloat var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(0.8)) } }

Slide 15

Slide 15 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @State var componentsOffset: CGFloat var topPadding: CGFloat private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity )) } } ͯ͞໰୊͸ ͜ͷcomponentsOffsetΛ Ͳ͏΍ͬͯऔΔ͔

Slide 16

Slide 16 text

public struct PositionReader: ViewModifier { struct PositionKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value += nextValue() } } var coordinateSpace: CoordinateSpace var position: KeyPath @Binding var value: CGFloat public func body(content: Content) -> some View { content .background( GeometryReader { geometry in Color.clear .preference(key: PositionKey.self, value: geometry.frame(in: coordinateSpace)[keyPath: position]) } ) .onPreferenceChange(PositionKey.self, perform: { newValue in value = newValue }) } } public extension View { func reading(_ keyPath: KeyPath, in coordinateSpace: CoordinateSpace, andAssignTo value: Binding) -> some View { self.modifier(PositionReader(coordinateSpace: coordinateSpace, position: keyPath, value: value)) } }

Slide 17

Slide 17 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @State var componentsOffset: CGFloat var topPadding: CGFloat @Namespace private var scrollView: Namespace.ID private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) .reading(\.minY, in: .named(scrollView), andAssignTo: $componentsOffset) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity )) .coordinateSpace(.named(scrollView)) } }

Slide 18

Slide 18 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @State var componentsOffset: CGFloat var topPadding: CGFloat @Namespace private var scrollView: Namespace.ID private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) .reading(\.minY, in: .named(scrollView), andAssignTo: $componentsOffset) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity)) .coordinateSpace(.named(scrollView)) .refreshable { reload() } } }

Slide 19

Slide 19 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN ԼʹΦʔόʔεΫϩʔϧ͚ͨ࣌ͩ͠ ը૾΋ҰॹʹԼ͕Γ·͢

Slide 20

Slide 20 text

struct PrimaryView: View { var topSpacing: CGFloat @State private var showsDialog = false var body: some View { VStack { Spacer() .frame(height: max(0, topSpacing)) Button { showsDialog = true } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } } .frame(maxHeight: .infinity, alignment: .top) .confirmationDialog("Message", isPresented: $showsDialog, actions: { Text("OK") }, message: { Text("ϋ΢εϘλϯ͕λοϓ͞Ε·ͨ͠") }) } }

Slide 21

Slide 21 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN εΫϩʔϧͷॳظҐஔΛ ը૾ͷԼʹ

Slide 22

Slide 22 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @State var componentsOffset: CGFloat var topPadding: CGFloat @Namespace private var scrollView: Namespace.ID private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) .reading(\.minY, in: .named(scrollView), andAssignTo: $componentsOffset) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity)) .coordinateSpace(.named(scrollView)) .refreshable { reload() } } } ͯ͞ࠓ౓ͷ໰୊͸ ͜ͷtopPaddingΛ Ͳ͏΍ͬͯऔΔ͔

Slide 23

Slide 23 text

struct PrimaryView: View { @Binding var baseImageHeight: CGFloat var topSpacing: CGFloat @State private var showsDialog = false var body: some View { VStack { Spacer() .frame(height: max(0, topSpacing)) Button { showsDialog = true } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } .reading(\.height, in: .local, andAssignTo: $baseImageHeight) } .frame(maxHeight: .infinity, alignment: .top) .confirmationDialog("Message", isPresented: $showsDialog, actions: { Text("OK") }, message: { Text("Did tap house button") }) } }

Slide 24

Slide 24 text

struct PrimaryView: View { @Binding var baseImageHeight: CGFloat var topSpacing: CGFloat @State private var showsDialog = false var body: some View { VStack { Spacer() .frame(height: max(0, topSpacing)) Button { showsDialog = true } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } .reading(\.height, in: .local, andAssignTo: $baseImageHeight) } .frame(maxHeight: .infinity, alignment: .top) .confirmationDialog("Message", isPresented: $showsDialog, actions: { Text("OK") }, message: { Text("Did tap house button") }) } }

Slide 25

Slide 25 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @Binding var componentsOffset: CGFloat var topPadding: CGFloat @Namespace private var scrollView: Namespace.ID private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) .reading(\.minY, in: .named(scrollView), andAssignTo: $componentsOffset) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity)) .coordinateSpace(.named(scrollView)) .refreshable { reload() } } }

Slide 26

Slide 26 text

struct BackgroundView: View { var body: some View { LinearGradient( colors: [ .mint.opacity(0.5), .cyan, ], startPoint: .top, endPoint: .center ) .ignoresSafeArea() } }

Slide 27

Slide 27 text

struct PrimaryView: View { @Binding var baseImageHeight: CGFloat var topSpacing: CGFloat @State private var showsDialog = false var body: some View { VStack { Spacer() .frame(height: max(0, topSpacing)) Button { showsDialog = true } label: { Image(systemName: "house.lodge.fill") .resizable() .scaledToFit() } .reading(\.height, in: .local, andAssignTo: $baseImageHeight) } .frame(maxHeight: .infinity, alignment: .top) .confirmationDialog("Message", isPresented: $showsDialog, actions: { Text("OK") }, message: { Text("Did tap house button") }) } }

Slide 28

Slide 28 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct OperationScrollView: View { @Binding var componentsOffset: CGFloat var topPadding: CGFloat @Namespace private var scrollView: Namespace.ID private var scrollViewOpacity: CGFloat { max(min((-componentsOffset-10) / topPadding, 0.8), 0) } var body: some View { ScrollView { LazyVGrid(columns: [GridItem(.flexible(minimum: 150, maximum: 300)), GridItem(.flexible(minimum: 150, maximum: 300))], content: { ForEach(0 ..< 20) { i in Text("Item: \(i)") .frame(maxWidth: .infinity) .frame(height: 100) .background(Color.blue) } }) .padding(.horizontal) .reading(\.minY, in: .named(scrollView), andAssignTo: $componentsOffset) } .safeAreaPadding(.top, topPadding) .background(Color.black.opacity(scrollViewOpacity)) .coordinateSpace(.named(scrollView)) .refreshable { reload() } } }

Slide 29

Slide 29 text

*UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN *UFN struct ContentView: View { @State private var baseImageHeight: CGFloat = 0 @State private var componentsOffset: CGFloat = 0 var body: some View { PrimaryView( baseImageHeight: $baseImageHeight, topSpacing: componentsOffset - baseImageHeight ) .overlay { OperationScrollView( componentsOffset: $componentsOffset, topPadding: baseImageHeight ) } .background { BackgroundView() } }

Slide 30

Slide 30 text

%FNP

Slide 31

Slide 31 text

͜ͷ࣮૷ʹ͸ͪΐͬͱ໰୊΋͋Γ·͢! w ݱ࣌఺Ͱ͸SFGSFTIBCMFʹBTZODॲཧΛೖΕΒΕͳ͍ w ಠࣗͰ3FGSFTI"DUJPOʹରԠ͢Ε͹͍͍ w IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPO TXJGUVJSFGSFTIBDUJPO

Slide 32

Slide 32 text

͜ͷ࣮૷ʹ͸ͪΐͬͱ໰୊΋͋Γ·͢! w TBGF"SFB1BEEJOHʹ΋ෆ౎߹͕͋Δ w άϧάϧͷҐஔ͕Լ͕͍ͬͯΔ w ্ʹεΫϩʔϧͨ͠ࡍ4BGF"SFBൣғͰ͸εΫϩʔ ϧϏϡʔʹ͋ΔϘλϯ͕λοϓͰ͖ͳ͍ w ୅ΘΓʹεΫϩʔϧϏϡʔͷҰ൪্ʹ4QBDFSΛೖΕ Δํ๏΋ߟ͑ΒΕΔ w ͦͷ৔߹εΫϩʔϧϏϡʔͷԼͷ1SJNBSZ7JFXͷ Ϙλϯ͕λοϓͰ͖ͳ͍

Slide 33

Slide 33 text

4XJGU6*໘౗ͤ͐͘

Slide 34

Slide 34 text

4XJGU6*໘౗ͤ͐͘ ୭͔ॿ͚͍ͯͩ͘͞ʂ