Skip to content

Commit

Permalink
Merge pull request #11 from juandahurt/tab
Browse files Browse the repository at this point in the history
feat: add tab view
  • Loading branch information
juandahurt authored Jun 2, 2022
2 parents 0e3e157 + b893219 commit afbfc1d
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 4 deletions.
28 changes: 24 additions & 4 deletions PuraceDemo/PuraceDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
2F1F7D7128317E0700AA30DB /* CollectionCardExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1F7D7028317E0700AA30DB /* CollectionCardExample.swift */; };
2F1F7D7328318D9900AA30DB /* TextExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1F7D7228318D9900AA30DB /* TextExample.swift */; };
2F1F7D7528318EEE00AA30DB /* ButtonExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F1F7D7428318EEE00AA30DB /* ButtonExample.swift */; };
2F27BC9D284814B600B5AC8D /* TabExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F27BC9C284814B600B5AC8D /* TabExample.swift */; };
2F77A234283C4AC700F143FB /* ImageExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F77A233283C4AC700F143FB /* ImageExample.swift */; };
2F9321B3282EE49E003DA929 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F9321B2282EE49E003DA929 /* AppDelegate.swift */; };
2F9321B5282EE49E003DA929 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F9321B4282EE49E003DA929 /* SceneDelegate.swift */; };
Expand All @@ -29,6 +30,7 @@
2F1F7D7028317E0700AA30DB /* CollectionCardExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionCardExample.swift; sourceTree = "<group>"; };
2F1F7D7228318D9900AA30DB /* TextExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextExample.swift; sourceTree = "<group>"; };
2F1F7D7428318EEE00AA30DB /* ButtonExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonExample.swift; sourceTree = "<group>"; };
2F27BC9C284814B600B5AC8D /* TabExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabExample.swift; sourceTree = "<group>"; };
2F77A233283C4AC700F143FB /* ImageExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageExample.swift; sourceTree = "<group>"; };
2F9321AF282EE49E003DA929 /* PuraceDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PuraceDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
2F9321B2282EE49E003DA929 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -58,16 +60,33 @@
2F1F7D6F28317DE200AA30DB /* Examples */ = {
isa = PBXGroup;
children = (
2F1F7D7028317E0700AA30DB /* CollectionCardExample.swift */,
2F27BC9B284814A700B5AC8D /* Complex */,
2F27BC9A2848149900B5AC8D /* Basic */,
);
path = Examples;
sourceTree = "<group>";
};
2F27BC9A2848149900B5AC8D /* Basic */ = {
isa = PBXGroup;
children = (
2F1F7D7228318D9900AA30DB /* TextExample.swift */,
2F1F7D7428318EEE00AA30DB /* ButtonExample.swift */,
2F072906283C00080098C5AF /* LoaderExample.swift */,
2F77A233283C4AC700F143FB /* ImageExample.swift */,
);
path = Basic;
sourceTree = "<group>";
};
2F27BC9B284814A700B5AC8D /* Complex */ = {
isa = PBXGroup;
children = (
2F1F7D7028317E0700AA30DB /* CollectionCardExample.swift */,
2FC004082831AC250037EF10 /* StoryExample.swift */,
2FA986782837351B000DB409 /* GridExample.swift */,
2FA9867A28373DD3000DB409 /* SnackbarExample.swift */,
2F072906283C00080098C5AF /* LoaderExample.swift */,
2F77A233283C4AC700F143FB /* ImageExample.swift */,
2F27BC9C284814B600B5AC8D /* TabExample.swift */,
);
path = Examples;
path = Complex;
sourceTree = "<group>";
};
2F9321A6282EE49E003DA929 = {
Expand Down Expand Up @@ -195,6 +214,7 @@
2F1F7D7528318EEE00AA30DB /* ButtonExample.swift in Sources */,
2FA986792837351B000DB409 /* GridExample.swift in Sources */,
2F9321B5282EE49E003DA929 /* SceneDelegate.swift in Sources */,
2F27BC9D284814B600B5AC8D /* TabExample.swift in Sources */,
2F072907283C00080098C5AF /* LoaderExample.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
64 changes: 64 additions & 0 deletions PuraceDemo/PuraceDemo/Examples/Complex/TabExample.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// TabExample.swift
// PuraceDemo
//
// Created by Juan Hurtado on 1/06/22.
//

import Foundation
import SwiftUI
import MapKit
import Purace

struct IdentifiablePlace: Identifiable {
let id: UUID
let location: CLLocationCoordinate2D
init(id: UUID = UUID(), lat: Double, long: Double) {
self.id = id
self.location = CLLocationCoordinate2D(
latitude: lat,
longitude: long)
}
}

struct TabExample: View {
let place = IdentifiablePlace(lat: 2.443881, long: -76.605059)
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 2.443881,
longitude: -76.605059),
latitudinalMeters: 750,
longitudinalMeters: 750
)

var body: some View {
PuraceTabView(titles: ["Acerca de", "Imágenes"]) { index in
Group {
switch index {
case 0:
VStack {
Map(coordinateRegion: $region, annotationItems: [place]) { item in
MapMarker(coordinate: place.location, tint: .black)
}.frame(height: UIScreen.main.bounds.height * 0.5)
Spacer(minLength: 0)
}
default:
ScrollView {
PuraceVerticalGridView(columns: 2, spacing: 1) {
PuraceImageView(url: URL(string: "https://www.biografiasyvidas.com/biografia/c/fotos/caldas_francisco_jose_2.jpg"))
.frame(height: 200)
PuraceImageView(url: URL(string: "https://www.biografiasyvidas.com/biografia/c/fotos/caldas_francisco_jose_2.jpg"))
.frame(height: 200)
PuraceImageView(url: URL(string: "https://www.biografiasyvidas.com/biografia/c/fotos/caldas_francisco_jose_2.jpg"))
.frame(height: 200)
PuraceImageView(url: URL(string: "https://www.biografiasyvidas.com/biografia/c/fotos/caldas_francisco_jose_2.jpg"))
.frame(height: 200)
}
}
}
}.frame(height: UIScreen.main.bounds.height * 0.7)
}.onAppear {
MKMapView.appearance().mapType = .mutedStandard
}
Spacer()
}
}
3 changes: 3 additions & 0 deletions PuraceDemo/PuraceDemo/MenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct MenuView: View {
NavigationLink("Grid") {
GridExample()
}
NavigationLink("Tab") {
TabExample()
}
}
}
.navigationTitle("Purace")
Expand Down
14 changes: 14 additions & 0 deletions Sources/Purace/Views/Complex/Tab/PuraceTabItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// PuraceTabItem.swift
//
//
// Created by Juan Hurtado on 1/06/22.
//

import Foundation
import SwiftUI

struct PuraceTabItem<T: View> {
let title: String
let content: () -> T
}
69 changes: 69 additions & 0 deletions Sources/Purace/Views/Complex/Tab/PuraceTabView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// PuraceTabView.swift
//
//
// Created by Juan Hurtado on 1/06/22.
//

import Foundation
import SwiftUI

public struct PuraceTabView<T: View>: View {
let titles: [String]
@State var selectedIndex = 0
@State var indicatorOffset: CGFloat = .zero
var viewForIndex: (Int) -> T

public init(titles: [String], viewForIndex: @escaping (Int) -> T) {
self.titles = titles
self.viewForIndex = viewForIndex
}

func headers(in size: CGSize) -> some View {
HStack(spacing: 0) {
ForEach(0..<titles.count) { index in
PuraceTextView(titles[index], fontSize: 12, textColor: selectedIndex == index ? PuraceStyle.Color.N1 : PuraceStyle.Color.N4, weight: selectedIndex == index ? .medium : .regular)
.frame(width: size.width / CGFloat(titles.count))
.onTapGesture {
selectedIndex = index
updateIndicatorOffset(size: size)
}
}
}.frame(height: 50)
}

func indicator(in size: CGSize) -> some View {
ZStack {
Color.black
.frame(height: 1)
.opacity(0.1)
HStack {
PuraceStyle.Color.B2
.frame(width: size.width / CGFloat(titles.count), height: 3)
Spacer(minLength: 0)
}.offset(x: indicatorOffset, y: 0)
}
}

func updateIndicatorOffset(size: CGSize) {
withAnimation(.linear(duration: 0.2)) {
indicatorOffset = CGFloat(selectedIndex) * size.width / CGFloat(titles.count)
}
}

public var body: some View {
GeometryReader { reader in
VStack(spacing: 0) {
headers(in: reader.size)
indicator(in: reader.size)
ZStack {
ForEach(0..<titles.count) { index in
viewForIndex(index)
.opacity(index == selectedIndex ? 1 : 0)
}
}.clipped()
.contentShape(Rectangle())
}
}
}
}

0 comments on commit afbfc1d

Please sign in to comment.