From 66ac194c38c78ea045578dc78ad6cdeb2bdc44d7 Mon Sep 17 00:00:00 2001 From: Tim Fraedrich Date: Sun, 17 Jan 2021 13:09:58 +0100 Subject: [PATCH 1/4] improved content handling --- Sources/SlidingTabView/SlidingTab.swift | 25 ++++ Sources/SlidingTabView/SlidingTabView.swift | 136 +++++++++++--------- 2 files changed, 101 insertions(+), 60 deletions(-) create mode 100644 Sources/SlidingTabView/SlidingTab.swift diff --git a/Sources/SlidingTabView/SlidingTab.swift b/Sources/SlidingTabView/SlidingTab.swift new file mode 100644 index 0000000..1fbd773 --- /dev/null +++ b/Sources/SlidingTabView/SlidingTab.swift @@ -0,0 +1,25 @@ +// +// File.swift +// +// +// Created by Tim Fraedrich on 17.01.21. +// + +import Foundation +import SwiftUI + +public struct SlidingTab { + + public let title: String + public let content: () -> AnyView + + public init(title: String, @ViewBuilder content: @escaping () -> Content) { + + self.title = title + self.content = { + AnyView(content()) + } + + } + +} diff --git a/Sources/SlidingTabView/SlidingTabView.swift b/Sources/SlidingTabView/SlidingTabView.swift index cfd54f6..7ff9b64 100644 --- a/Sources/SlidingTabView/SlidingTabView.swift +++ b/Sources/SlidingTabView/SlidingTabView.swift @@ -24,7 +24,6 @@ import SwiftUI -@available(iOS 13.0, *) public struct SlidingTabView : View { // MARK: Internal State @@ -41,8 +40,8 @@ public struct SlidingTabView : View { /// Binding the selection index which will re-render the consuming view @Binding var selection: Int - /// The title of the tabs - let tabs: [String] + /// The list of tabs + let tabs: [SlidingTab] // Mark: View Customization Properties @@ -58,6 +57,9 @@ public struct SlidingTabView : View { /// The accent color when the tab is not selected let inactiveAccentColor: Color + /// The height of the tabs. + let tabHeight: CGFloat + /// The color of the selection bar let selectionBarColor: Color @@ -79,11 +81,12 @@ public struct SlidingTabView : View { // MARK: init public init(selection: Binding, - tabs: [String], + tabs: SlidingTab..., font: Font = .body, animation: Animation = .spring(), activeAccentColor: Color = .blue, inactiveAccentColor: Color = Color.black.opacity(0.4), + tabHeight: CGFloat = 50, selectionBarColor: Color = .blue, inactiveTabColor: Color = .clear, activeTabColor: Color = .clear, @@ -96,6 +99,7 @@ public struct SlidingTabView : View { self.animation = animation self.activeAccentColor = activeAccentColor self.inactiveAccentColor = inactiveAccentColor + self.tabHeight = tabHeight self.selectionBarColor = selectionBarColor self.inactiveTabColor = inactiveTabColor self.activeTabColor = activeTabColor @@ -109,50 +113,65 @@ public struct SlidingTabView : View { public var body: some View { assert(tabs.count > 1, "Must have at least 2 tabs") - return VStack(alignment: .leading, spacing: 0) { - HStack(spacing: 0) { - ForEach(self.tabs, id:\.self) { tab in - Button(action: { - let selection = self.tabs.firstIndex(of: tab) ?? 0 - self.selectionState = selection - }) { - HStack { - Spacer() - Text(tab).font(self.font) - Spacer() + return ZStack { + + VStack(alignment: .leading, spacing: 0) { + + Group { + HStack(spacing: 0) { + + ForEach(0.. Bool { - return tabs[selectionState] == tabIdentifier + private func isSelected(tabIndex: Int) -> Bool { + return selectionState == tabIndex } private func selectionBarXOffset(from totalWidth: CGFloat) -> CGFloat { @@ -165,30 +184,27 @@ public struct SlidingTabView : View { } #if DEBUG - -@available(iOS 13.0, *) -struct SlidingTabConsumerView : View { - @State private var selectedTabIndex = 0 - - var body: some View { - VStack(alignment: .leading) { - SlidingTabView(selection: self.$selectedTabIndex, - tabs: ["First", "Second"], - font: .body, - activeAccentColor: Color.blue, - selectionBarColor: Color.blue) - (selectedTabIndex == 0 ? Text("First View") : Text("Second View")).padding() - Spacer() - } - .padding(.top, 50) - .animation(.none) - } -} - -@available(iOS 13.0.0, *) struct SlidingTabView_Previews : PreviewProvider { + + @State static var selectedTab = 0 + static var previews: some View { - SlidingTabConsumerView() + SlidingTabView( + selection: $selectedTab, + tabs: SlidingTab(title: "Hello") { + + Text("Hello") + + }, + SlidingTab(title: "World!") { + + Text("World!") + + }, + font: .body, + activeAccentColor: Color.blue, + selectionBarColor: Color.blue + ) } } #endif From e14d49457f7b27665083a1c44cbed654357f8f2c Mon Sep 17 00:00:00 2001 From: Tim Fraedrich Date: Sun, 17 Jan 2021 13:10:32 +0100 Subject: [PATCH 2/4] updated Package.swift --- Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.swift b/Package.swift index 0b07719..8d836b5 100644 --- a/Package.swift +++ b/Package.swift @@ -5,6 +5,7 @@ import PackageDescription let package = Package( name: "SlidingTabView", + platforms: [.iOS(.v13)], products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. .library( From 2ef8364801c3c5d3316594303730905195a4dc12 Mon Sep 17 00:00:00 2001 From: Tim Fraedrich Date: Sun, 17 Jan 2021 13:11:53 +0100 Subject: [PATCH 3/4] updated README.md --- README.md | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 841f0ca..5d3461e 100644 --- a/README.md +++ b/README.md @@ -9,32 +9,28 @@ Please use Swift Package Manager to install **SlidingTabView** ## Usage -Just instantiate and bind it to your state. That is it! +Just instantiate, bind it to your state and add your tabs with their respective content. That is it! ```swift -@State private var selectedTabIndex = 0 -SlidingTabView(selection: $selectedTabIndex,tabs: ["First Tab", "Second Tab"] -``` +import SlidingTabView -## Canvas Preview -```swift -struct SlidingTabConsumerView : View { - @State private var selectedTabIndex = 0 +struct MyView: View { + + @State var selectedTab: Int = 0 var body: some View { - VStack(alignment: .leading) { - SlidingTabView(selection: self.$selectedTabIndex, tabs: ["First", "Second"]) - (selectedTabIndex == 0 ? Text("First View") : Text("Second View")).padding() - Spacer() - } - .padding(.top, 50) - .animation(.none) - } -} + SlidingTabView( + selection: $selectedTab, + tabs: SlidingTab(title: "Hello") { + + Text("Hello") + + }, + SlidingTab(title: "World!") { + + Text("World!") -@available(iOS 13.0.0, *) -struct SlidingTabView_Previews : PreviewProvider { - static var previews: some View { - SlidingTabConsumerView() + } + ) } } ``` From 09e04c498641b6b68a0d20f8e199a1b427d09791 Mon Sep 17 00:00:00 2001 From: Tim Fraedrich Date: Sun, 17 Jan 2021 13:16:35 +0100 Subject: [PATCH 4/4] added license to new file --- Sources/SlidingTabView/SlidingTab.swift | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Sources/SlidingTabView/SlidingTab.swift b/Sources/SlidingTabView/SlidingTab.swift index 1fbd773..15d788b 100644 --- a/Sources/SlidingTabView/SlidingTab.swift +++ b/Sources/SlidingTabView/SlidingTab.swift @@ -1,8 +1,25 @@ // -// File.swift +// SlidingTab.swift // +// Copyright (c) 2019 Quynh Nguyen // -// Created by Tim Fraedrich on 17.01.21. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. // import Foundation