Skip to content

Commit

Permalink
Patch 0.5.1
Browse files Browse the repository at this point in the history
style:
- Scale & Cube Rotation animations reworked

chore:
- Minor code refactoring
  • Loading branch information
FulcrumOne authored May 21, 2024
1 parent 0a5cdeb commit a0efde2
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 46 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,5 @@ DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
.swiftpm/xcode/package.xcworkspace/xcshareddata
>>>>>>> bfd2701 (Initial Commit)

This file was deleted.

6 changes: 2 additions & 4 deletions Sources/Internal/Managers/NavigationManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SwiftUI

public class NavigationManager: ObservableObject {
@Published private(set) var views: [AnyNavigatableView] = [] { willSet { onViewsWillUpdate(newValue) } }
@Published private(set) var transitionsBlocked: Bool = false
private(set) var transitionsBlocked: Bool = false
private(set) var transitionType: TransitionType = .push
private(set) var transitionAnimation: TransitionAnimation = .no

Expand All @@ -26,9 +26,7 @@ extension NavigationManager {
}
extension NavigationManager {
static func performOperation(_ operation: Operation) { if !NavigationManager.shared.transitionsBlocked {
DispatchQueue.main.async { withAnimation(nil) {
shared.views.perform(operation)
}}
DispatchQueue.main.async { shared.views.perform(operation) }
}}
}

Expand Down
70 changes: 36 additions & 34 deletions Sources/Internal/Views/NavigationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,21 @@ struct NavigationView: View {
@ObservedObject private var stack: NavigationManager = .shared
@ObservedObject private var screenManager: ScreenManager = .shared
@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
@State private var animatableData: AnimatableData = .init()
private let config: NavigationGlobalConfig


init(rootView: some NavigatableView, config: NavigationGlobalConfig?) {
NavigationManager.setRoot(rootView)

self.config = config ?? .init()
self._temporaryViews = .init(initialValue: NavigationManager.shared.views)
}
init(rootView: some NavigatableView, config: NavigationGlobalConfig?) { NavigationManager.setRoot(rootView); self.config = config ?? .init() }
var body: some View {
ZStack { ForEach(temporaryViews, id: \.id, content: createItem) }
.ignoresSafeArea(.container)
.onChange(of: stack.views, perform: onViewsChanged)
.onAnimationCompleted(for: animatableOpacity, perform: onAnimationCompleted)
.onAnimationCompleted(for: animatableData.opacity, perform: onAnimationCompleted)
}
}
private extension NavigationView {
func createItem(_ item: AnyNavigatableView) -> some View {
item
item.body
.padding(.top, getTopPadding(item))
.padding(.bottom, getBottomPadding(item))
.frame(maxWidth: .infinity, maxHeight: .infinity)
Expand Down Expand Up @@ -84,7 +76,7 @@ private extension NavigationView {
return view == lastView
}
func calculateOpacityValue(_ isLastView: Bool) -> CGFloat {
isLastView ? animatableOpacity : 1 - animatableOpacity
isLastView ? animatableData.opacity : 1 - animatableData.opacity
}
func calculateFinalOpacityValue(_ opacity: CGFloat) -> CGFloat { switch stack.transitionAnimation {
case .no, .dissolve, .scale: opacity
Expand All @@ -96,7 +88,7 @@ private extension NavigationView {
private extension NavigationView {
func getOffset(_ view: AnyNavigatableView) -> CGSize { guard canCalculateOffset(view) else { return .zero }
let offsetSlideValue = calculateSlideOffsetValue(view)
let offset = animatableOffset + offsetSlideValue
let offset = animatableData.offset + offsetSlideValue
let offsetX = calculateXOffsetValue(offset), offsetY = calculateYOffsetValue(offset)
let finalOffset = calculateFinalOffsetValue(view, offsetX, offsetY)
return finalOffset
Expand Down Expand Up @@ -135,8 +127,8 @@ private extension NavigationView {
return true
}
func calculateScaleValue(_ view: AnyNavigatableView) -> CGFloat { switch view == temporaryViews.last {
case true: stack.transitionType == .push ? 1 - scaleFactor + animatableScale : 1 - animatableScale
case false: stack.transitionType == .push ? 1 + animatableScale : 1 + scaleFactor - animatableScale
case true: stack.transitionType == .push ? 1 - scaleFactor + animatableData.scale : 1 - animatableData.scale
case false: stack.transitionType == .push ? 1 + animatableData.scale : 1 + scaleFactor - animatableData.scale
}}
func calculateFinalScaleValue(_ scaleValue: CGFloat) -> CGFloat { stack.transitionsBlocked ? scaleValue : 1 }
}
Expand All @@ -155,8 +147,8 @@ private extension NavigationView {
let rotationTranslation = calculateRotationTranslationValue(view)
return rotationTranslation
}
func getRotationAxis() -> (x: CGFloat, y: CGFloat, z: CGFloat) { (x: 0, y: 1, z: 0) }
func getRotationPerspective() -> CGFloat { 1.8 }
func getRotationAxis() -> (x: CGFloat, y: CGFloat, z: CGFloat) { (x: 0.000000000001, y: 1, z: 0) }
func getRotationPerspective() -> CGFloat { 1.6 }
}
private extension NavigationView {
func canCalculateRotation(_ view: AnyNavigatableView) -> Bool {
Expand All @@ -165,20 +157,21 @@ private extension NavigationView {
return true
}
func calculateRotationAngleValue(_ view: AnyNavigatableView) -> Angle { switch view == temporaryViews.last {
case true: .degrees(90 + -animatableRotation * 90)
case false: .degrees(-animatableRotation * 90)
case true: .degrees(90 + -animatableData.rotation * 90)
case false: .degrees(-animatableData.rotation * 90)
}}
func calculateRotationTranslationValue(_ view: AnyNavigatableView) -> CGFloat { switch view == temporaryViews.last {
case true: screenManager.size.width - (animatableRotation * screenManager.size.width)
case false: -1 * (animatableRotation * screenManager.size.width)
case true: screenManager.size.width - (animatableData.rotation * screenManager.size.width)
case false: -1 * (animatableData.rotation * screenManager.size.width)
}}
}

// MARK: - Animation
private extension NavigationView {
func getAnimation() -> Animation { switch stack.transitionAnimation {
case .no: .easeInOut(duration: 0)
case .scale, .dissolve, .horizontalSlide, .verticalSlide: .spring(duration: 0.36, bounce: 0, blendDuration: 0.1)
case .dissolve, .horizontalSlide, .verticalSlide: .spring(duration: 0.36, bounce: 0, blendDuration: 0.1)
case .scale: .snappy
case .cubeRotation: .easeOut(duration: 0.52)
}}
}
Expand All @@ -203,16 +196,16 @@ private extension NavigationView {
func resetOffsetAndOpacity() {
let animatableOffsetFactor = stack.transitionType == .push ? 1.0 : -1.0

animatableOffset = maxOffsetValue * animatableOffsetFactor
animatableOpacity = 0
animatableRotation = stack.transitionType == .push ? 0 : 1
animatableScale = 0
animatableData.offset = maxOffsetValue * animatableOffsetFactor
animatableData.opacity = 0
animatableData.rotation = stack.transitionType == .push ? 0 : 1
animatableData.scale = 0
}
func animateOffsetAndOpacityChange() { withAnimation(getAnimation()) {
animatableOffset = 0
animatableOpacity = 1
animatableRotation = 1 - animatableRotation
animatableScale = scaleFactor
animatableData.offset = 0
animatableData.opacity = 1
animatableData.rotation = 1 - animatableData.rotation
animatableData.scale = scaleFactor
}}
}

Expand All @@ -230,15 +223,24 @@ private extension NavigationView {
func resetViewOnAnimationCompleted() {
if stack.transitionType == .pop {
temporaryViews = stack.views
animatableOffset = -maxOffsetValue
animatableRotation = 1
animatableData.offset = -maxOffsetValue
animatableData.rotation = 1
}
}
}

// MARK: - Configurables
private extension NavigationView {
var scaleFactor: CGFloat { 0.38 }
var scaleFactor: CGFloat { 0.46 }
var maxXOffsetValueWhileRemoving: CGFloat { screenManager.size.width * 0.33 }
var maxOffsetValue: CGFloat { [.horizontalSlide: screenManager.size.width, .verticalSlide: screenManager.size.height][stack.transitionAnimation] ?? 0 }
}


// MARK: - Animatable Data
fileprivate struct AnimatableData {
var opacity: CGFloat = 1
var offset: CGFloat = 0
var rotation: CGFloat = 0
var scale: CGFloat = 0
}

0 comments on commit a0efde2

Please sign in to comment.