From 7b905896137fde0ad67c311f24dd256f27fa305f Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 19:28:04 -0500 Subject: [PATCH 1/7] Update to use ViewBuilder --- .../CLAnimatedTabView/CLAnimatedTabView.swift | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index e337319..cbf2005 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -20,24 +20,20 @@ public struct CLAnimatedTabView: View { @State var currentTab: Int = 0 @ObservedObject var viewModel: CLAnimatedTabViewModel - var views: [Content] + private let injectedView: () -> Content - public init(viewModel: CLAnimatedTabViewModel, _ views: Content...) { + public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> Content) { self.viewModel = viewModel - self.views = views + self.injectedView = injectedView } public var body: some View { ZStack(alignment: .top) { - TabView(selection: $currentTab) { - ForEach(views.indices, id: \.self) { index in - views[index] - } - } - .tabViewStyle(.page(indexDisplayMode: .never)) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) - .animation(.easeInOut, value: currentTab) - .padding(.top, viewModel.tabBarHeight) + TabView(selection: $currentTab, content: injectedView) + .tabViewStyle(.page(indexDisplayMode: .never)) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) + .animation(.easeInOut, value: currentTab) + .padding(.top, viewModel.tabBarHeight) TabBarView(currentTab: $currentTab, tabBarItemNames: $viewModel.tabNames, From c9eaca4e3c00aba901561b3fd9ad567da34501ea Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 19:58:31 -0500 Subject: [PATCH 2/7] Try tuple view --- .../CLAnimatedTabView/CLAnimatedTabView.swift | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index cbf2005..b26210f 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -20,20 +20,24 @@ public struct CLAnimatedTabView: View { @State var currentTab: Int = 0 @ObservedObject var viewModel: CLAnimatedTabViewModel - private let injectedView: () -> Content + private let injectedView: [AnyView] - public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> Content) { + public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> TupleView) { self.viewModel = viewModel - self.injectedView = injectedView + self.injectedView = injectedView().getViews } public var body: some View { ZStack(alignment: .top) { - TabView(selection: $currentTab, content: injectedView) - .tabViewStyle(.page(indexDisplayMode: .never)) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) - .animation(.easeInOut, value: currentTab) - .padding(.top, viewModel.tabBarHeight) + TabView(selection: $currentTab) { + ForEach(injectedView.indices, id: \.self) { index in + injectedView[index] + } + } + .tabViewStyle(.page(indexDisplayMode: .never)) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) + .animation(.easeInOut, value: currentTab) + .padding(.top, viewModel.tabBarHeight) TabBarView(currentTab: $currentTab, tabBarItemNames: $viewModel.tabNames, @@ -138,3 +142,30 @@ struct CLTabViewButtonStyle: ButtonStyle { } } #endif + + +extension TupleView { + var getViews: [AnyView] { + makeArray(from: value) + } + + private struct GenericView { + let body: Any + + var anyView: AnyView? { + AnyView(_fromValue: body) + } + } + + private func makeArray(from tuple: Tuple) -> [AnyView] { + func convert(child: Mirror.Child) -> AnyView? { + withUnsafeBytes(of: child.value) { ptr -> AnyView? in + let binded = ptr.bindMemory(to: GenericView.self) + return binded.first?.anyView + } + } + + let tupleMirror = Mirror(reflecting: tuple) + return tupleMirror.children.compactMap(convert) + } +} From b14143b194bf0fc588c85464e5818ed7af78e0b5 Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 20:01:50 -0500 Subject: [PATCH 3/7] Add generic for 'Views' --- Sources/CLAnimatedTabView/CLAnimatedTabView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index b26210f..d3e9497 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -22,7 +22,7 @@ public struct CLAnimatedTabView: View { @ObservedObject var viewModel: CLAnimatedTabViewModel private let injectedView: [AnyView] - public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> TupleView) { + public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> TupleView) { self.viewModel = viewModel self.injectedView = injectedView().getViews } From 361a006c718b2fa494f7f1c7a5fa2394a4e3adc9 Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 20:02:59 -0500 Subject: [PATCH 4/7] Remove Content --- Sources/CLAnimatedTabView/CLAnimatedTabView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index d3e9497..0f716eb 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -16,7 +16,7 @@ import Foundation import SwiftUI #if os(iOS) -public struct CLAnimatedTabView: View { +public struct CLAnimatedTabView: View { @State var currentTab: Int = 0 @ObservedObject var viewModel: CLAnimatedTabViewModel From 5699905dbf142dfbf1e43aaabe8032d177b2b852 Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 20:09:27 -0500 Subject: [PATCH 5/7] Move TupleView Extension to own file --- .../CLAnimatedTabView/CLAnimatedTabView.swift | 27 -------------- Sources/Extensions/TupleView_GetViews.swift | 35 +++++++++++++++++++ 2 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 Sources/Extensions/TupleView_GetViews.swift diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index 0f716eb..3f1cbd1 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -142,30 +142,3 @@ struct CLTabViewButtonStyle: ButtonStyle { } } #endif - - -extension TupleView { - var getViews: [AnyView] { - makeArray(from: value) - } - - private struct GenericView { - let body: Any - - var anyView: AnyView? { - AnyView(_fromValue: body) - } - } - - private func makeArray(from tuple: Tuple) -> [AnyView] { - func convert(child: Mirror.Child) -> AnyView? { - withUnsafeBytes(of: child.value) { ptr -> AnyView? in - let binded = ptr.bindMemory(to: GenericView.self) - return binded.first?.anyView - } - } - - let tupleMirror = Mirror(reflecting: tuple) - return tupleMirror.children.compactMap(convert) - } -} diff --git a/Sources/Extensions/TupleView_GetViews.swift b/Sources/Extensions/TupleView_GetViews.swift new file mode 100644 index 0000000..0a8ea5e --- /dev/null +++ b/Sources/Extensions/TupleView_GetViews.swift @@ -0,0 +1,35 @@ +// +// TupleView_GetViews.swift +// +// +// Created by Chris Larsen on 5/7/24. +// referenced from George's answer here: https://stackoverflow.com/questions/64238485/how-to-loop-over-viewbuilder-content-subviews-in-swiftui +// + +import SwiftUI + +extension TupleView { + var getViews: [AnyView] { + makeArray(from: value) + } + + private struct GenericView { + let body: Any + + var anyView: AnyView? { + AnyView(_fromValue: body) + } + } + + private func makeArray(from tuple: Tuple) -> [AnyView] { + func convert(child: Mirror.Child) -> AnyView? { + withUnsafeBytes(of: child.value) { ptr -> AnyView? in + let binded = ptr.bindMemory(to: GenericView.self) + return binded.first?.anyView + } + } + + let tupleMirror = Mirror(reflecting: tuple) + return tupleMirror.children.compactMap(convert) + } +} From 5fab619acc377d293da27cefbee006add1ab92fa Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 20:17:29 -0500 Subject: [PATCH 6/7] Move back internal extension --- .../CLAnimatedTabView/CLAnimatedTabView.swift | 28 +++++++++++++++ Sources/Extensions/TupleView_GetViews.swift | 35 ------------------- 2 files changed, 28 insertions(+), 35 deletions(-) delete mode 100644 Sources/Extensions/TupleView_GetViews.swift diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index 3f1cbd1..58ef42a 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -142,3 +142,31 @@ struct CLTabViewButtonStyle: ButtonStyle { } } #endif + +// referenced from George's answer here: https://stackoverflow.com/questions/64238485/how-to-loop-over-viewbuilder-content-subviews-in-swiftui +// MARK: TupleView extension +extension TupleView { + var getViews: [AnyView] { + makeArray(from: value) + } + + private struct GenericView { + let body: Any + + var anyView: AnyView? { + AnyView(_fromValue: body) + } + } + + private func makeArray(from tuple: Tuple) -> [AnyView] { + func convert(child: Mirror.Child) -> AnyView? { + withUnsafeBytes(of: child.value) { ptr -> AnyView? in + let binded = ptr.bindMemory(to: GenericView.self) + return binded.first?.anyView + } + } + + let tupleMirror = Mirror(reflecting: tuple) + return tupleMirror.children.compactMap(convert) + } +} diff --git a/Sources/Extensions/TupleView_GetViews.swift b/Sources/Extensions/TupleView_GetViews.swift deleted file mode 100644 index 0a8ea5e..0000000 --- a/Sources/Extensions/TupleView_GetViews.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// TupleView_GetViews.swift -// -// -// Created by Chris Larsen on 5/7/24. -// referenced from George's answer here: https://stackoverflow.com/questions/64238485/how-to-loop-over-viewbuilder-content-subviews-in-swiftui -// - -import SwiftUI - -extension TupleView { - var getViews: [AnyView] { - makeArray(from: value) - } - - private struct GenericView { - let body: Any - - var anyView: AnyView? { - AnyView(_fromValue: body) - } - } - - private func makeArray(from tuple: Tuple) -> [AnyView] { - func convert(child: Mirror.Child) -> AnyView? { - withUnsafeBytes(of: child.value) { ptr -> AnyView? in - let binded = ptr.bindMemory(to: GenericView.self) - return binded.first?.anyView - } - } - - let tupleMirror = Mirror(reflecting: tuple) - return tupleMirror.children.compactMap(convert) - } -} From d9eea7a075c7a26a2c6f68e9acf783dd24a613e1 Mon Sep 17 00:00:00 2001 From: Chris Larsen Date: Tue, 7 May 2024 20:21:36 -0500 Subject: [PATCH 7/7] Make plural --- Sources/CLAnimatedTabView/CLAnimatedTabView.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift index 58ef42a..94f8e12 100644 --- a/Sources/CLAnimatedTabView/CLAnimatedTabView.swift +++ b/Sources/CLAnimatedTabView/CLAnimatedTabView.swift @@ -20,18 +20,18 @@ public struct CLAnimatedTabView: View { @State var currentTab: Int = 0 @ObservedObject var viewModel: CLAnimatedTabViewModel - private let injectedView: [AnyView] + private let injectedViews: [AnyView] - public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedView: @escaping () -> TupleView) { + public init(viewModel: CLAnimatedTabViewModel, @ViewBuilder injectedViews: @escaping () -> TupleView) { self.viewModel = viewModel - self.injectedView = injectedView().getViews + self.injectedViews = injectedViews().getViews } public var body: some View { ZStack(alignment: .top) { TabView(selection: $currentTab) { - ForEach(injectedView.indices, id: \.self) { index in - injectedView[index] + ForEach(injectedViews.indices, id: \.self) { index in + injectedViews[index] } } .tabViewStyle(.page(indexDisplayMode: .never))