3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_AKGPushAnimatorTableviewDemoUITestsVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_AKGPushAnimatorTableviewDemoUITestsVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Examples/AKGPushAnimatorTableviewDemo/Pods/Target Support Files/Pods-AKGPushAnimatorTableviewDemoUITests/Pods-AKGPushAnimatorTableviewDemoUITests.debug.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/AKGPushAnimator"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/AKGPushAnimator/AKGPushAnimator.framework/Headers"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/Examples/AKGPushAnimatorTableviewDemo/Pods/Target Support Files/Pods-AKGPushAnimatorTableviewDemoUITests/Pods-AKGPushAnimatorTableviewDemoUITests.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_AKGPushAnimatorTableviewDemoUITests {
2 | umbrella header "Pods-AKGPushAnimatorTableviewDemoUITests-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/AKGPushAnimatorTableviewDemo/Pods/Target Support Files/Pods-AKGPushAnimatorTableviewDemoUITests/Pods-AKGPushAnimatorTableviewDemoUITests.release.xcconfig:
--------------------------------------------------------------------------------
1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/AKGPushAnimator"
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/AKGPushAnimator/AKGPushAnimator.framework/Headers"
5 | PODS_BUILD_DIR = $BUILD_DIR
6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ahmet Günay
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AKGPushAnimator
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Easily Push and Pop viewcontroller like Instagram App with Interaction written in pure Swift 4
21 |
22 | 
23 |
24 | ## Import Library To Your Class
25 |
26 | If you are using Carthage to install AKGPushAnimator, then you need to import AKGPushAnimatorKit where you want to use.
27 | Because "Carthage" needs Embedded Framework to install libraries, and AKGPushAnimatorKit is the embedded library name of this project.
28 |
29 | If you are using Cocoapods to install AKGPushAnimator, then you need to import AKGPushAnimator where you want to use it.
30 |
31 | ## Usage
32 |
33 | Usage is simple with creating any BaseViewController and implement UINavigationControllerDelegate
34 |
35 |
36 | ```swift
37 |
38 | class BaseViewController: UIViewController, UINavigationControllerDelegate {
39 |
40 | let pushAnimator = AKGPushAnimator()
41 | let interactionAnimator = AKGInteractionAnimator()
42 |
43 | override func viewDidLoad() {
44 | super.viewDidLoad()
45 | }
46 |
47 | func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
48 |
49 | if operation == .push {
50 | interactionAnimator.attachToViewController(toVC)
51 | }
52 | pushAnimator.isReverseTransition = operation == .pop
53 | return pushAnimator
54 | }
55 |
56 | func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
57 |
58 | return interactionAnimator.transitionInProgress ? interactionAnimator : nil
59 | }
60 | }
61 | ```
62 |
63 | After that, create any ViewController inheritted from BaseViewController and set navigationcontroller delegate before pushing viewcontroller (in prepare for segue for best)
64 |
65 | And Thats all! Now you have interactive push and pop animation like Instagram App.
66 |
67 | ```swift
68 |
69 | class FirstViewController: BaseViewController {
70 |
71 | override func viewDidLoad() {
72 | super.viewDidLoad()
73 | pushAnimator.delegate = self
74 | }
75 |
76 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
77 | if segue.identifier == "showSecond" {
78 | navigationController?.delegate = self
79 | }
80 | }
81 |
82 | override func didReceiveMemoryWarning() {
83 | super.didReceiveMemoryWarning()
84 | }
85 | }
86 |
87 | ```
88 |
89 | #### Delegation Pattern
90 |
91 | ```swift
92 |
93 | extension FirstViewController: AKGPushAnimatorDelegate {
94 |
95 | func beganTransition() {
96 | print("began transition")
97 | }
98 |
99 | func cancelledTransition() {
100 | print("cancelled transition")
101 | }
102 |
103 | func finishedTransition() {
104 | print("finished transition")
105 | }
106 | }
107 |
108 | ```
109 |
110 | #### Customise Animation with constants
111 |
112 | AKGPushAnimator has constants file to easily change animation types:
113 |
114 | ```swift
115 | struct Common {
116 | static let duration = 0.27;
117 | static let dismissPosition : CGFloat = -50;
118 | static let shadowOpacity : Float = 1
119 | static let shadowColor : UIColor = .black
120 | }
121 |
122 | struct Push {
123 | static let animateOption = UIViewAnimationOptions.curveEaseOut
124 |
125 | }
126 |
127 | struct Pop {
128 | static let animateOption = UIViewAnimationOptions.curveEaseInOut
129 | }
130 |
131 | ```
132 | ## Installation
133 |
134 | There are three ways to use AKGPushAnimator in your project:
135 | - using CocoaPods
136 | - using Carthage
137 | - by cloning the project into your repository
138 |
139 | ### Installation with CocoaPods
140 |
141 | [CocoaPods](http://cocoapods.org/) is a dependency manager for Swift and Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the [Get Started](http://cocoapods.org/#get_started) section for more details.
142 |
143 | #### Podfile
144 | ```ruby
145 | platform :ios, '8.0'
146 | use_frameworks!
147 | pod 'AKGPushAnimator', '~> 1.0.6'
148 | ```
149 |
150 | ### Installation with Carthage
151 |
152 | [Carthage](https://github.com/Carthage/Carthage) is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods.
153 |
154 | To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage)
155 |
156 | #### Cartfile
157 | ```
158 | github "ahmetkgunay/AKGPushAnimator" ~> 1.0.6
159 | ```
160 |
161 | ## Author
162 |
163 | Ahmet Kazım Günay, ahmetkgunay@gmail.com
164 |
165 | ## License
166 |
167 | AKGPushAnimator is available under the MIT license. See the LICENSE file for more info.
168 |
169 |
--------------------------------------------------------------------------------
/Source/AKGInteractionAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AKGInteractionAnimator.swift
3 | // AKGPushAnimatorDemo
4 | //
5 | // Created by AHMET KAZIM GUNAY on 30/04/2017.
6 | // Copyright © 2017 AHMET KAZIM GUNAY. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class AKGInteractionAnimator: UIPercentDrivenInteractiveTransition {
12 |
13 | var navigationController: UINavigationController!
14 | var shouldCompleteTransition = false
15 | public var transitionInProgress = false
16 |
17 | public func attachToViewController(_ viewController: UIViewController) {
18 | navigationController = viewController.navigationController
19 | addGestureRecognizer(viewController.view)
20 | }
21 |
22 | fileprivate func addGestureRecognizer(_ view: UIView) {
23 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(AKGInteractionAnimator.handlePanGesture(_:)))
24 | panGesture.delegate = self
25 | view.addGestureRecognizer(panGesture)
26 | }
27 |
28 | @objc func handlePanGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
29 | let viewTranslation = gestureRecognizer.translation(in: gestureRecognizer.view?.superview)
30 | let velocity : CGPoint = gestureRecognizer.velocity(in: gestureRecognizer.view)
31 |
32 | switch gestureRecognizer.state {
33 | case .began:
34 | transitionInProgress = true
35 | navigationController.popViewController(animated: true)
36 | case .changed:
37 | var const = CGFloat(viewTranslation.x / UIScreen.main.bounds.width * 1.0)
38 | const = min(1.0, max(0.0, const))
39 | shouldCompleteTransition = const > 0.5 || velocity.x > UIScreen.main.bounds.width
40 | update(const)
41 | case .cancelled, .ended:
42 | transitionInProgress = false
43 | if !shouldCompleteTransition || gestureRecognizer.state == .cancelled {
44 | cancel()
45 | } else {
46 | finish()
47 | }
48 | default:
49 | print("Swift switch must be exhaustive, thus the default")
50 | }
51 | }
52 | }
53 |
54 | extension AKGInteractionAnimator : UIGestureRecognizerDelegate {
55 |
56 | private func gestureRecognizerShouldBegin(_ gestureRecognizer: UIPanGestureRecognizer) -> Bool {
57 | let velocity : CGPoint = gestureRecognizer.velocity(in: gestureRecognizer.view)
58 | return fabs(velocity.x) > fabs(velocity.y) && fabs(velocity.x) > 0;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Source/AKGPushAnimator.h:
--------------------------------------------------------------------------------
1 | //
2 | // AKGPushAnimator.h
3 | // AKGPushAnimator
4 | //
5 | // Created by AHMET KAZIM GUNAY on 07/05/2017.
6 | // Copyright © 2017 AHMET KAZIM GUNAY. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for AKGPushAnimator.
12 | FOUNDATION_EXPORT double AKGPushAnimatorVersionNumber;
13 |
14 | //! Project version string for AKGPushAnimator.
15 | FOUNDATION_EXPORT const unsigned char AKGPushAnimatorVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Source/AKGPushAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AKGPushAnimator.swift
3 | // AKGPushAnimatorDemo
4 | //
5 | // Created by AHMET KAZIM GUNAY on 30/04/2017.
6 | // Copyright © 2017 AHMET KAZIM GUNAY. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc public protocol AKGPushAnimatorDelegate {
12 |
13 | @objc optional func beganTransition()
14 | @objc optional func cancelledTransition()
15 | @objc optional func finishedTransition()
16 | }
17 |
18 | public class AKGPushAnimator: NSObject {
19 |
20 | public var isReverseTransition = false
21 |
22 | open var delegate : AKGPushAnimatorDelegate?
23 |
24 | // MARK: Variables with Getters
25 |
26 | var animatorScreenWidth : CGFloat {
27 | get {
28 | return UIScreen.main.bounds.width
29 | }
30 | }
31 |
32 | var animatorScreenHeight : CGFloat {
33 | get {
34 | return UIScreen.main.bounds.height
35 | }
36 | }
37 |
38 | var toViewPushedFrame : CGRect {
39 | get {
40 | return CGRect(x : 0,
41 | y : 0,
42 | width : self.animatorScreenWidth,
43 | height : self.animatorScreenHeight)
44 | }
45 | }
46 |
47 | var fromViewPushedFrame : CGRect {
48 | get {
49 | return CGRect(x : AKGPushAnimatorConstants.Common.dismissPosition,
50 | y : 0,
51 | width : self.animatorScreenWidth,
52 | height : self.animatorScreenHeight)
53 | }
54 | }
55 |
56 | var fromViewPopedFrame : CGRect {
57 | get {
58 | return CGRect(x : self.animatorScreenWidth,
59 | y : 0,
60 | width : self.animatorScreenWidth,
61 | height : self.animatorScreenHeight)
62 | }
63 | }
64 |
65 | var toViewPopedFrame : CGRect {
66 | get {
67 | return CGRect(x : 0,
68 | y : 0,
69 | width : self.animatorScreenWidth,
70 | height : self.animatorScreenHeight)
71 | }
72 | }
73 |
74 | fileprivate func animate(withTransitionContext transitionContext:UIViewControllerContextTransitioning,
75 | toView: UIView,
76 | fromView: UIView,
77 | duration: TimeInterval,
78 | delay: TimeInterval,
79 | options: UIViewAnimationOptions = [],
80 | animations: @escaping () -> Swift.Void) {
81 |
82 | UIView.animate(withDuration: duration,
83 | delay: delay,
84 | options: options,
85 | animations: animations) { (finished) in
86 |
87 | if (transitionContext.transitionWasCancelled) {
88 | toView.removeFromSuperview()
89 | self.delegate?.cancelledTransition?()
90 | } else {
91 | fromView.removeFromSuperview()
92 | self.delegate?.finishedTransition?()
93 | }
94 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
95 |
96 | }
97 | }
98 |
99 | fileprivate func addShadowToView(_ toView:UIView!) -> Swift.Void {
100 |
101 | toView.layer.shadowOpacity = AKGPushAnimatorConstants.Common.shadowOpacity
102 | toView.layer.shadowOffset = CGSize(width:0, height:3)
103 | toView.layer.shadowColor = AKGPushAnimatorConstants.Common.shadowColor.cgColor
104 | let shadowRect: CGRect = toView.bounds.insetBy(dx: 0, dy: 4); // inset top/bottom
105 | toView.layer.shadowPath = UIBezierPath(rect: shadowRect).cgPath
106 | }
107 | }
108 |
109 | extension AKGPushAnimator: UIViewControllerAnimatedTransitioning {
110 |
111 | // MARK: UIViewControllerAnimatedTransitioning
112 |
113 | public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
114 | return AKGPushAnimatorConstants.Common.duration
115 | }
116 |
117 | public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
118 |
119 | let containerView = transitionContext.containerView
120 |
121 | guard let toVC = transitionContext.viewController(forKey: .to),
122 | let fromVC = transitionContext.viewController(forKey: .from),
123 | let toView = toVC.view,
124 | let fromView = fromVC.view else { return }
125 |
126 | addShadowToView(toView)
127 |
128 | delegate?.beganTransition?()
129 |
130 | if !isReverseTransition {
131 |
132 | containerView.addSubview(fromView)
133 | containerView.addSubview(toView)
134 |
135 | toView.frame = CGRect(x : animatorScreenWidth,
136 | y : toView.frame.origin.y,
137 | width : animatorScreenWidth,
138 | height : animatorScreenHeight)
139 |
140 | animate(withTransitionContext: transitionContext,
141 | toView: toView,
142 | fromView: fromView,
143 | duration: AKGPushAnimatorConstants.Common.duration,
144 | delay: 0,
145 | options: AKGPushAnimatorConstants.Push.animateOption,
146 | animations: {
147 | fromView.frame = self.fromViewPushedFrame
148 | toView.frame = self.toViewPushedFrame})
149 | }
150 | else {
151 |
152 | containerView.addSubview(toView)
153 | containerView.addSubview(fromView)
154 |
155 | toView.frame = CGRect(x : AKGPushAnimatorConstants.Common.dismissPosition,
156 | y : toView.frame.origin.y,
157 | width : animatorScreenWidth,
158 | height : animatorScreenHeight)
159 |
160 | animate(withTransitionContext: transitionContext,
161 | toView: toView,
162 | fromView: fromView,
163 | duration: AKGPushAnimatorConstants.Common.duration,
164 | delay: 0,
165 | options: AKGPushAnimatorConstants.Pop.animateOption,
166 | animations: {
167 | fromView.frame = self.fromViewPopedFrame
168 | toView.frame = self.toViewPopedFrame })
169 | }
170 | }
171 | }
172 |
173 |
--------------------------------------------------------------------------------
/Source/AKGPushAnimatorConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AKGPushAnimatorConstants.swift
3 | // AKGPushAnimatorDemo
4 | //
5 | // Created by AHMET KAZIM GUNAY on 30/04/2017.
6 | // Copyright © 2017 AHMET KAZIM GUNAY. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | struct AKGPushAnimatorConstants {
12 |
13 | struct Common {
14 | static let duration = 0.27
15 | static let dismissPosition : CGFloat = -50
16 | static let shadowOpacity : Float = 1
17 | static let shadowColor : UIColor = .black
18 | }
19 |
20 | struct Push {
21 | static let animateOption : UIViewAnimationOptions = .curveEaseOut
22 |
23 | }
24 |
25 | struct Pop {
26 | static let animateOption : UIViewAnimationOptions = .curveEaseInOut
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Source/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------