From 3b994cd981d9a3ff7f25e5c738f7a30fcb92309f Mon Sep 17 00:00:00 2001 From: fermoya Date: Mon, 20 Jan 2020 22:01:07 +0000 Subject: [PATCH] Adding support for Cocoapods --- .DS_Store | Bin 8196 -> 8196 bytes Package.swift | 3 +- Sample.xcodeproj/project.pbxproj | 69 +++++------ .../contents.xcworkspacedata | 2 +- .../xcshareddata/swiftpm/Package.resolved | 16 +++ Sample/ContentView.swift | 1 + Sample/Pager/Helpers/Buildable.swift | 21 ---- Sample/Pager/Helpers/SizeViewModifier.swift | 40 ------- Sample/Pager/Helpers/View+Helper.swift | 15 --- Sample/Pager/Pager+Buildable.swift | 53 -------- Sample/Pager/Pager+Helper.swift | 113 ------------------ Sample/Pager/Pager.swift | 108 ----------------- Sources/SwiftUIPager/Pager.swift | 19 ++- SwiftUIPader.podspec | 24 ++++ SwiftUIPager/.gitignore | 5 - SwiftUIPager/README.md | 3 - 16 files changed, 85 insertions(+), 407 deletions(-) create mode 100644 Sample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 Sample/Pager/Helpers/Buildable.swift delete mode 100644 Sample/Pager/Helpers/SizeViewModifier.swift delete mode 100644 Sample/Pager/Helpers/View+Helper.swift delete mode 100644 Sample/Pager/Pager+Buildable.swift delete mode 100644 Sample/Pager/Pager+Helper.swift delete mode 100644 Sample/Pager/Pager.swift create mode 100644 SwiftUIPader.podspec delete mode 100644 SwiftUIPager/.gitignore delete mode 100644 SwiftUIPager/README.md diff --git a/.DS_Store b/.DS_Store index c5393b789eec7b46cebef4ffb239700a8a364998..aa06de38d9195dc9c61a613f1d291c6fa05c06a7 100644 GIT binary patch delta 161 zcmZp1XmOa}&nUJrU^hRb*k&GqU(8I)6(&1~s7=-r;bLW5BNnMK*;d3D&QhN|M}&{@ z!{*f@=8Th##kIIu8A2FR8HyQ77>Xya5x60a#4igj%FD^mOJ`tUVBA>9$hetZ;x;QO JnkE+h0|5A + location = "self:"> diff --git a/Sample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Sample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..519dc29 --- /dev/null +++ b/Sample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "SwiftUIPager", + "repositoryURL": "https://github.com/fermoya/SwiftUIPager", + "state": { + "branch": "master", + "revision": "47d877a00ff1aeb8a6f0eb7e8d6d1301834c66c3", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/Sample/ContentView.swift b/Sample/ContentView.swift index e0c1020..cb928fb 100644 --- a/Sample/ContentView.swift +++ b/Sample/ContentView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import SwiftUIPager extension Int: Identifiable { public var id: Int { return self } diff --git a/Sample/Pager/Helpers/Buildable.swift b/Sample/Pager/Helpers/Buildable.swift deleted file mode 100644 index d7a872b..0000000 --- a/Sample/Pager/Helpers/Buildable.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Buildable.swift -// iPod -// -// Created by Fernando Moya de Rivas on 09/12/2019. -// Copyright © 2019 Fernando Moya de Rivas. All rights reserved. -// - -import Foundation - -protocol Buildable { } - -extension Buildable { - - func mutating(keyPath: WritableKeyPath, value: T) -> Self { - var newSelf = self - newSelf[keyPath: keyPath] = value - return newSelf - } - -} diff --git a/Sample/Pager/Helpers/SizeViewModifier.swift b/Sample/Pager/Helpers/SizeViewModifier.swift deleted file mode 100644 index 3847511..0000000 --- a/Sample/Pager/Helpers/SizeViewModifier.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// SizeViewModifier.swift -// SwiftUIPager -// -// Created by Fernando Moya de Rivas on 19/01/2020. -// Copyright © 2020 Fernando Moya de Rivas. All rights reserved. -// - -import SwiftUI - -struct SizePreferenceKey: PreferenceKey { - static var defaultValue: CGSize = .zero - - static func reduce(value: inout CGSize, nextValue: () -> CGSize) { - value = nextValue() - } -} - -struct SizeViewModifier: ViewModifier { - - @Binding var size: CGSize - - func body(content: Content) -> some View { - GeometryReader { proxy in - content - .preference(key: SizePreferenceKey.self, - value: proxy.size) - }.onPreferenceChange(SizePreferenceKey.self, perform: { (newSize) in - self.size = newSize - }) - } -} - -extension View { - - func sizeTrackable(_ size: Binding) -> some View { - self.modifier(SizeViewModifier(size: size)) - } - -} diff --git a/Sample/Pager/Helpers/View+Helper.swift b/Sample/Pager/Helpers/View+Helper.swift deleted file mode 100644 index 557ff58..0000000 --- a/Sample/Pager/Helpers/View+Helper.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// View+Helper.swift -// SwiftUIPager -// -// Created by Fernando Moya de Rivas on 19/01/2020. -// Copyright © 2020 Fernando Moya de Rivas. All rights reserved. -// - -import SwiftUI - -extension View { - func frame(size: CGSize) -> some View { - frame(width: size.width, height: size.height) - } -} diff --git a/Sample/Pager/Pager+Buildable.swift b/Sample/Pager/Pager+Buildable.swift deleted file mode 100644 index 7197465..0000000 --- a/Sample/Pager/Pager+Buildable.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// Pager+ViewModifiers.swift -// SwiftUIPager -// -// Created by Fernando Moya de Rivas on 19/01/2020. -// Copyright © 2020 Fernando Moya de Rivas. All rights reserved. -// - -import SwiftUI - -extension Pager: Buildable { - - func interactive(_ scale: CGFloat) -> Self { - let scale = min(1, abs(scale)) - return mutating(keyPath: \.interactiveScale, value: scale) - } - - func pageOffset(_ pageOffset: Double) -> Self { - let contentOffset = CGFloat(pageOffset) * pageDistance - return mutating(keyPath: \.contentOffset, value: contentOffset) - } - - func itemShadowColor(_ color: Color) -> Self { - mutating(keyPath: \.shadowColor, value: color) - } - - func itemSpacing(_ value: CGFloat) -> Self { - mutating(keyPath: \.itemSpacing, value: value) - } - - func pageAspectRatio(_ value: CGFloat) -> Self { - mutating(keyPath: \.pageAspectRatio, value: value) - } - - func onPageChanged(_ onPageChanged: ((Int) -> Void)?) -> Self { - mutating(keyPath: \.onPageChanged, value: onPageChanged) - } - - func padding(_ length: CGFloat) -> Self { - padding(.all, length) - } - - func padding(_ insets: EdgeInsets) -> Self { - let length = min(insets.top, insets.bottom) - return padding(.vertical, length) - } - - func padding(_ edges: Edge.Set = .all, _ length: CGFloat? = nil) -> Self { - guard edges == .all || edges == .vertical else { return self } - return mutating(keyPath: \.verticalInsets, value: length ?? 8) - } - -} diff --git a/Sample/Pager/Pager+Helper.swift b/Sample/Pager/Pager+Helper.swift deleted file mode 100644 index 01f8573..0000000 --- a/Sample/Pager/Pager+Helper.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// Pager+Helper.swift -// SwiftUIPager -// -// Created by Fernando Moya de Rivas on 19/01/2020. -// Copyright © 2020 Fernando Moya de Rivas. All rights reserved. -// - -import SwiftUI - -extension Pager { - - var scaleIncrement: CGFloat { 1 - interactiveScale } - var interactiveItemSpacing: CGFloat { itemSpacing - (pageSize.width * scaleIncrement) / 2 } - var isDragging: Bool { abs(totalOffset) > 0 } - - var direction: Direction? { - guard totalOffset != 0 else { return nil } - return totalOffset < 0 ? .forward : .backward - } - - var currentPage: Int { - guard isDragging else { return page } - let newPage = -Int((totalOffset / self.pageDistance).rounded()) + self.page - return max(min(newPage, self.numberOfPages - 1), 0) - } - - var offsetLowerbound: CGFloat { - guard currentPage == 0 else { return CGFloat(numberOfPages) * self.size.width } - return CGFloat(numberOfPagesDisplayed) / 2 * pageDistance - pageDistance / 4 - } - - var offsetUpperbound: CGFloat { - guard currentPage == numberOfPages - 1 else { return -CGFloat(numberOfPages) * self.size.width } - return -CGFloat(numberOfPagesDisplayed) / 2 * pageDistance + pageDistance / 4 - } - - var totalOffset: CGFloat { - draggingOffset + contentOffset - } - - var pageSize: CGSize { - let size = CGSize(width: self.size.width - 2 * verticalInsets, - height: self.size.height - 2 * verticalInsets) - let side = min(size.width, size.height) - if pageAspectRatio > 1 { - return CGSize(width: side, height: side / pageAspectRatio) - } else { - return CGSize(width: side * pageAspectRatio, height: side) - } - } - - var pageDistance: CGFloat { - pageSize.width + self.interactiveItemSpacing - } - - var numberOfPages: Int { data.count } - - var maximumNumberOfPages: Int { - guard pageDistance != 0 else { return 0 } - return Int((CGFloat(recyclingRatio) * size.width / pageDistance / 2).rounded(.up)) - } - - var numberOfPagesDisplayed: Int { - upperPageDisplayed - lowerPageDisplayed - } - - var dataDisplayed: [Data] { - Array(data[lowerPageDisplayed.. CGFloat { - guard isDragging else { return isFocused(item) ? 1 : interactiveScale } - - let totalIncrement = abs(totalOffset / pageDistance) - let currentPage = direction == .forward ? CGFloat(page) + totalIncrement : CGFloat(page) - totalIncrement - - guard let indexInt = data.firstIndex(of: item) else { return interactiveScale } - - let index = CGFloat(indexInt) - guard abs(currentPage - index) <= 1 else { return interactiveScale } - - let increment = totalIncrement - totalIncrement.rounded(.towardZero) - let nextPage = direction == .forward ? currentPage.rounded(.awayFromZero) : currentPage.rounded(.towardZero) - guard currentPage > 0 else { - return 1 - (scaleIncrement * increment) - } - - return index == nextPage ? interactiveScale + (scaleIncrement * increment) - : 1 - (scaleIncrement * increment) - } - - func isFocused(_ item: Data) -> Bool { - data.firstIndex(of: item) == currentPage - } - -} diff --git a/Sample/Pager/Pager.swift b/Sample/Pager/Pager.swift deleted file mode 100644 index c98992b..0000000 --- a/Sample/Pager/Pager.swift +++ /dev/null @@ -1,108 +0,0 @@ -// -// Pager.swift -// SwiftUIPager -// -// Created by Fernando Moya de Rivas on 05/12/2019. -// Copyright © 2019 Fernando Moya de Rivas. All rights reserved. -// - -import SwiftUI - -struct Pager: View where Content: View, Data: Identifiable & Equatable { - - enum Direction { - case forward, backward - } - - /** Constants **/ - - /// Should be greather than 1 - let recyclingRatio = 4 - - /** Dependencies **/ - - let content: (Data) -> Content - var data: [Data] - - /** ViewModified properties **/ - - var interactiveScale: CGFloat = 1 - var contentOffset: CGFloat = 0 - var shadowColor: Color = .clear - var onPageChanged: ((Int) -> Void)? - var verticalInsets: CGFloat = 0 - var itemSpacing: CGFloat = 0 - var pageAspectRatio: CGFloat = 1 - - /** Dragging offset **/ - - @State var size: CGSize = .zero - @State var draggingOffset: CGFloat = 0 - @State var draggingStartTime: Date! = nil - @Binding var page: Int { - didSet { - onPageChanged?(page) - } - } - - init(page: Binding, data: [Data], pageAspectRatio: CGFloat = 1, content: @escaping (Data) -> Content) { - self._page = page - self.pageAspectRatio = max(0, pageAspectRatio) - self.data = data - self.content = content - } - - var body: some View { - HStack(spacing: self.interactiveItemSpacing) { - ForEach(self.dataDisplayed) { item in - self.content(item) - .frame(size: self.pageSize) - .scaleEffect(self.scale(for: item)) - .onTapGesture (perform: { - withAnimation(.spring()) { - self.scrollToItem(item) - } - }).shadow(color: self.shadowColor, radius: 5) - .transition(.identity) - } - .offset(x: self.xOffset, y : 0) - } - .clipped() - .gesture(self.swipeGesture) - .sizeTrackable($size) - } -} - -// MARK: Gestures - -extension Pager { - - func scrollToItem(_ item: Data) { - guard let index = data.firstIndex(of: item) else { return } - self.page = index - } - - var swipeGesture: some Gesture { - DragGesture() - .onChanged({ value in - withAnimation { - self.draggingStartTime = self.draggingStartTime ?? value.time - self.draggingOffset = value.translation.width - } - }).onEnded({ (value) in - let velocity = -Double(value.translation.width) / value.time.timeIntervalSince(self.draggingStartTime ?? Date()) - var newPage = self.currentPage - if newPage == self.page, abs(velocity) > 1000 { - newPage = newPage + Int(velocity / velocity) - } - newPage = max(0, min(self.numberOfPages - 1, newPage)) - withAnimation(.easeOut) { - self.page = newPage - self.draggingOffset = 0 - self.draggingStartTime = nil - } - } - ) - } - -} diff --git a/Sources/SwiftUIPager/Pager.swift b/Sources/SwiftUIPager/Pager.swift index f1ec713..5e3c954 100644 --- a/Sources/SwiftUIPager/Pager.swift +++ b/Sources/SwiftUIPager/Pager.swift @@ -8,23 +8,30 @@ import SwiftUI +/** + Horizontal + */ public struct Pager: View where Content: View, Data: Identifiable & Equatable { + /// `Direction` determines the direction of the swipe gesture enum Direction { case forward, backward } - /** Constants **/ + /*** Constants ***/ - /// Should be greather than 1 + /// Manages the number of items that should be displayed in the screen. + /// A ratio of 3, for instance, would mean the items held in memory are enough + /// to cover 3 times the size of the pager let recyclingRatio = 4 - /** Dependencies **/ + /*** Dependencies ***/ + /// let content: (Data) -> Content var data: [Data] - /** ViewModified properties **/ + /*** ViewModified properties ***/ var interactiveScale: CGFloat = 1 var contentOffset: CGFloat = 0 @@ -34,7 +41,7 @@ public struct Pager: View where Content: View, Data: Identifiabl var itemSpacing: CGFloat = 0 var pageAspectRatio: CGFloat = 1 - /** Dragging offset **/ + /*** Dragging offset ***/ @State var size: CGSize = .zero @State var draggingOffset: CGFloat = 0 @@ -45,7 +52,7 @@ public struct Pager: View where Content: View, Data: Identifiabl } } - public init(page: Binding, data: [Data], pageAspectRatio: CGFloat = 1, content: @escaping (Data) -> Content) { + public init(page: Binding, data: [Data], pageAspectRatio: CGFloat = 1, @ViewBuilder content: @escaping (Data) -> Content) { self._page = page self.pageAspectRatio = max(0, pageAspectRatio) self.data = data diff --git a/SwiftUIPader.podspec b/SwiftUIPader.podspec new file mode 100644 index 0000000..7845c47 --- /dev/null +++ b/SwiftUIPader.podspec @@ -0,0 +1,24 @@ +Pod::Spec.new do |s| + + s.name = "SwiftUIPager" + s.version = "0.0.1" + s.summary = "Native horizontal pager for SwiftUI. Easily to use, easy to customize." + + s.description = <<-DESC + This framework provides a horizontal pager build with native SwiftUI views. Views are recycled, so you don't have to worry about memory issues. It's very easy to use and lets you customize it. For example, you can change the aspect ratio of the page displayed, the spacing between pages or you can make it interactive. + DESC + + s.homepage = "https://medium.com/@fmdr.ct" + s.license = { :type => "MIT", :file => "LICENSE" } + s.author = { "fermoya" => "fmdr.ct@gmail.com" } + + s.platforms = { :ios => "13.0", :osx => "10.15", :watchos => "6.0"" } + s.swift_version = '5.1' + + s.source = { :git => "https://github.com/fermoya/SwiftUIPager.git", :tag => "#{s.version}" } + s.source_files = "Sources/SwiftUIPager/**/*" + + s.xcconfig = { "SWIFT_VERSION" => "5.1" } + s.documentation_url = "https://github.com/fermoya/SwiftUIPager/blob/master/README.md" + +end \ No newline at end of file diff --git a/SwiftUIPager/.gitignore b/SwiftUIPager/.gitignore deleted file mode 100644 index 95c4320..0000000 --- a/SwiftUIPager/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ diff --git a/SwiftUIPager/README.md b/SwiftUIPager/README.md deleted file mode 100644 index d02bf68..0000000 --- a/SwiftUIPager/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# SwiftUIPager - -A description of this package.