Skip to content

Commit

Permalink
New Features + Bug Fixes
Browse files Browse the repository at this point in the history
feat:
- Added Cube Rotation transition
- Added onFocus modifier

refactor:
- Please use MijickNavigattie instead of Navigattie when importing the library in your project

style:
- Changed the value of the horizontal transition offset
- Changed the value of the scale transition

docs:
- Documentation updated

fix:
- Fixed an issue with the view not filling the entire screen.
  • Loading branch information
FulcrumOne authored Sep 17, 2023
1 parent 9e04369 commit 214a9fb
Show file tree
Hide file tree
Showing 19 changed files with 129 additions and 37 deletions.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ let package = Package(
.iOS(.v15)
],
products: [
.library(name: "Navigattie", targets: ["Navigattie"]),
.library(name: "MijickNavigattie", targets: ["MijickNavigattie"]),
],
targets: [
.target(name: "Navigattie", dependencies: [])
.target(name: "MijickNavigattie", dependencies: [], path: "Sources")
]
)
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<br>

<p align="center">
<img alt="Navigattie Logo" src="https://github.com/Mijick/Navigattie/assets/23524947/ea9f1fd8-0ee8-4064-87ca-baa316e44085" width="88%"">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/Mijick/Assets/blob/main/Navigattie/Logotype/On%20Dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/Mijick/Assets/blob/main/Navigattie/Logotype/On%20Light.svg">
<img alt="Navigattie Logo" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Logotype/On%20Dark.svg" width="76%"">
</picture>
</p>

<h3 style="font-size: 5em" align="center">
Expand All @@ -19,27 +23,24 @@
<br>

<p align="center">
<img alt="Library in beta version" src="https://github.com/Mijick/Navigattie/assets/23524947/b698aaac-4a91-431b-a7ef-f1dda28304b6"/>
<img alt="Designed for SwiftUI" src="https://github.com/Mijick/Navigattie/assets/23524947/822de7e5-481e-49c0-b55b-653ac0de86bb"/>
<img alt="Platforms: iOS" src="https://github.com/Mijick/Navigattie/assets/23524947/58399b94-5fa0-4c29-9013-ba52f6c3b63e"/>
<img alt="Release: 0.3.2" src="https://github.com/Mijick/Navigattie/assets/23524947/3dd389f8-a8bd-4c2b-a3c6-3c089d05d1cb"/>
<a href="https://www.swift.org/package-manager">
<img alt="Swift Package Manager: Compatible" src="https://github.com/Mijick/Navigattie/assets/23524947/a4876e58-6a26-40c3-97bb-b5e6f69423d9"/>
</a>
<img alt="License: MIT" src="https://github.com/Mijick/Navigattie/assets/23524947/de233cae-4517-462a-86ac-5618f91b1d4a"/>
<img alt="Library in beta version" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Beta.svg"/>
<img alt="Designed for SwiftUI" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Language.svg"/>
<img alt="Platforms: iOS" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Platforms.svg"/>
<img alt="Current Version" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Version.svg"/>
<img alt="License: MIT" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/License.svg"/>
</p>

<p align="center">
<a href="https://github.com/Mijick/Navigattie/stargazers">
<img alt="Stars" src="https://github.com/Mijick/Navigattie/assets/23524947/f9d35612-7925-4b8e-99ad-74c983f59293"/>
</a>
<img alt="Made in Kraków" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Origin.svg"/>
<a href="https://twitter.com/MijickTeam">
<img alt="Follow us on Twitter" src="https://github.com/Mijick/Navigattie/assets/23524947/2d4d094e-36fa-48c5-8f92-46f5c1ce5c82"/>
<img alt="Follow us on X" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/X.svg"/>
</a>
<a href=mailto:[email protected]?subject=Hello>
<img alt="Let's work together" src="https://github.com/Mijick/Navigattie/assets/23524947/803e0227-41fc-4d65-8ccb-ce5dfc1b4319"/>
</a>
<img alt="Made in Kraków" src="https://github.com/Mijick/Navigattie/assets/23524947/f18e87d5-6684-4aa6-9339-757e9b3fd83b"/>
<img alt="Let's work together" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Work%20with%20us.svg"/>
</a>
<a href="https://github.com/Mijick/Navigattie/stargazers">
<img alt="Stargazers" src="https://github.com/Mijick/Assets/blob/main/Navigattie/Labels/Stars.svg"/>
</a>
</p>

<p align="center">
Expand Down Expand Up @@ -179,12 +180,14 @@ Navigattie is released under the MIT license. See [LICENSE][License] for details

# Our other open source SwiftUI libraries
[PopupView] - The most powerful popup library that allows you to present any popup

<br>
[GridView] - Lay out your data with no effort

[MIT]: https://en.wikipedia.org/wiki/MIT_License
[SPM]: https://www.swift.org/package-manager
[Demo]: https://github.com/Mijick/Navigattie-Demo
[License]: https://github.com/Mijick/Navigattie/blob/main/LICENSE
[PopupView]: https://github.com/Mijick/PopupView
[PopupView]: https://github.com/Mijick/PopupView
[GridView]: https://github.com/Mijick/GridView
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct NavigationStackView: View {
@State private var temporaryViews: [AnyNavigatableView] = []
@State private var animatableOpacity: CGFloat = 1
@State private var animatableOffset: CGFloat = 0
@State private var animatableRotation: CGFloat = 0
@State private var animatableScale: CGFloat = 0
private let config: NavigationGlobalConfig

Expand All @@ -39,11 +40,14 @@ private extension NavigationStackView {
item
.padding(.top, getTopPadding(item))
.padding(.bottom, getBottomPadding(item))
.scaleEffect(getScale(item))
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(getBackground(item))
.transition(.identity)
.opacity(getOpacity(item))
.scaleEffect(getScale(item))
.offset(getOffset(item))
.offset(x: getRotationTranslation(item))
.rotation3DEffect(getRotationAngle(item), axis: getRotationAxis(), anchor: getRotationAnchor(item), perspective: getRotationPerspective())
.compositingGroup()
}
}
Expand Down Expand Up @@ -93,7 +97,7 @@ private extension NavigationStackView {
func calculateFinalOpacityValue(_ opacity: CGFloat) -> CGFloat {
switch stack.transitionAnimation {
case .no, .dissolve, .scale: return opacity
case .horizontalSlide, .verticalSlide: return stack.transitionsBlocked ? 1 : opacity
case .horizontalSlide, .verticalSlide, .cubeRotation: return stack.transitionsBlocked ? 1 : opacity
}
}
}
Expand Down Expand Up @@ -159,6 +163,65 @@ private extension NavigationStackView {
func calculateFinalScaleValue(_ scaleValue: CGFloat) -> CGFloat { stack.transitionsBlocked ? scaleValue : 1 }
}

// MARK: - Calculating Rotation
private extension NavigationStackView {
func getRotationAngle(_ view: AnyNavigatableView) -> Angle {
do {
try checkRotationPrerequisites(view)

let angle = calculateRotationAngleValue(view)
return angle
} catch { return .zero }
}
func getRotationAnchor(_ view: AnyNavigatableView) -> UnitPoint {
switch view == temporaryViews.last {
case true: return .trailing
case false: return .leading
}
}
func getRotationTranslation(_ view: AnyNavigatableView) -> CGFloat {
do {
try checkRotationPrerequisites(view)

let rotationTranslation = calculateRotationTranslationValue(view)
return rotationTranslation
} catch {
return 0
}
}
func getRotationAxis() -> (x: CGFloat, y: CGFloat, z: CGFloat) { (x: 0, y: 1, z: 0) }
func getRotationPerspective() -> CGFloat { 1.8 }
}
private extension NavigationStackView {
func checkRotationPrerequisites(_ view: AnyNavigatableView) throws {
if !stack.transitionAnimation.isOne(of: .cubeRotation) { throw "Rotation cannot be set for a non-rotation transition type" }
if !view.isOne(of: temporaryViews.last, temporaryViews.nextToLast) { throw "Rotation can concern the last or next to last element of the stack" }
}
func calculateRotationAngleValue(_ view: AnyNavigatableView) -> Angle {
switch view == temporaryViews.last {
case true: return .degrees(90 - (animatableRotation * 90))
case false: return .degrees(-(animatableRotation * 90))
}
}
func calculateRotationTranslationValue(_ view: AnyNavigatableView) -> CGFloat {
switch view == temporaryViews.last {
case true: return UIScreen.width - (animatableRotation * UIScreen.width)
case false: return -1 * (animatableRotation * UIScreen.width)
}
}
}

// MARK: - Animation
private extension NavigationStackView {
func getAnimation() -> Animation {
switch stack.transitionAnimation {
case .no: return .easeInOut(duration: 0)
case .scale, .dissolve, .horizontalSlide, .verticalSlide: return .spring(response: 0.4, dampingFraction: 1, blendDuration: 0.4)
case .cubeRotation: return .easeOut(duration: 0.6)
}
}
}

// MARK: - On Transition Begin
private extension NavigationStackView {
func onViewsChanged(_ views: [AnyNavigatableView]) {
Expand All @@ -183,11 +246,13 @@ private extension NavigationStackView {

animatableOffset = maxOffsetValue * animatableOffsetFactor
animatableOpacity = 0
animatableRotation = stack.transitionType == .push ? 0 : 1
animatableScale = 0
}
func animateOffsetAndOpacityChange() { withAnimation(animation) {
func animateOffsetAndOpacityChange() { withAnimation(getAnimation()) {
animatableOffset = 0
animatableOpacity = 1
animatableRotation = 1 - animatableRotation
animatableScale = scaleFactor
}}
}
Expand All @@ -207,14 +272,14 @@ private extension NavigationStackView {
if stack.transitionType == .pop {
temporaryViews = stack.views
animatableOffset = -maxOffsetValue
animatableRotation = 1
}
}
}

// MARK: - Configurables
private extension NavigationStackView {
var scaleFactor: CGFloat { 0.33 }
var maxXOffsetValueWhileRemoving: CGFloat { UIScreen.width * 0.2 }
var scaleFactor: CGFloat { 0.38 }
var maxXOffsetValueWhileRemoving: CGFloat { UIScreen.width * 0.33 }
var maxOffsetValue: CGFloat { [.horizontalSlide: UIScreen.width, .verticalSlide: UIScreen.height][stack.transitionAnimation] ?? 0 }
var animation: Animation { stack.transitionAnimation == .no ? .easeInOut(duration: 0) : .spring(response: 0.44, dampingFraction: 1, blendDuration: 0.4) }
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,8 @@ public extension NavigatableView {
func configure(view: NavigationConfig) -> NavigationConfig { view }
}

// MARK: - Pushing And Removing Views From Stack
// MARK: - Pushing Views To Stack
public extension NavigatableView {
/// Pushes a new view. Stacks previous one
func push(with animation: TransitionAnimation) { NavigationManager.push(self, animation) }
}
public extension View {
/// Removes the presented view from the stack
func pop() { NavigationManager.pop() }

/// Removes all views up to the selected view in the stack. The view from the argument will be the new active view
func pop<N: NavigatableView>(to view: N.Type) { NavigationManager.pop(to: view) }

/// Removes all views from the stack. Root view will be the new active view
func popToRoot() { NavigationManager.popToRoot() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ public enum TransitionAnimation {
case dissolve
case scale
case horizontalSlide, verticalSlide
case cubeRotation
}
33 changes: 33 additions & 0 deletions Sources/Public/Public+View.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Public+View.swift of Navigattie
//
// Created by Tomasz Kurylik
// - Twitter: https://twitter.com/tkurylik
// - Mail: [email protected]
//
// Copyright ©2023 Mijick. Licensed under MIT License.


import SwiftUI

// MARK: - Removing Views From Stack
public extension View {
/// Removes the presented view from the stack
func pop() { NavigationManager.pop() }

/// Removes all views up to the selected view in the stack. The view from the argument will be the new active view
func pop<N: NavigatableView>(to view: N.Type) { NavigationManager.pop(to: view) }

/// Removes all views from the stack. Root view will be the new active view
func popToRoot() { NavigationManager.popToRoot() }
}

// MARK: - Actions
public extension View {
/// Triggers every time the popup is at the top of the stack
func onFocus(_ view: some NavigatableView, perform action: @escaping () -> ()) -> some View {
onReceive(NavigationManager.shared.$views) { views in
if views.last?.id == view.id { action() }
}
}
}

0 comments on commit 214a9fb

Please sign in to comment.