├── .gitignore ├── ChildInteractiveTransition.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /ChildInteractiveTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChildInteractiveTransition.swift 3 | // 4 | // 5 | // Created by Dmitry Ratkevich on 3/8/15. 6 | // Copyright (c) 2015 Dmitry Ratkevich. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let CITParalaxCoefficient: CGFloat = 0.6 12 | let CITMinPercentageToFinish: CGFloat = 0.15 13 | let CITDuration = 0.2 14 | 15 | enum ChildInteractiveTransitionDirection { 16 | case Left 17 | case Right 18 | } 19 | 20 | class ChildInteractiveTransitionViewController: UIViewController { 21 | func updateTransition(percentComplete: CGFloat, direction: ChildInteractiveTransitionDirection, presenting: Bool, duration: NSTimeInterval?) { 22 | 23 | } 24 | 25 | func cancelTransition(direction: ChildInteractiveTransitionDirection, presenting: Bool, duration: NSTimeInterval?) { 26 | self.updateTransition(0.0, direction: direction, presenting: presenting, duration: duration) 27 | } 28 | 29 | func finishTransition(direction: ChildInteractiveTransitionDirection, presenting: Bool, duration: NSTimeInterval?) { 30 | self.updateTransition(1.0, direction: direction, presenting: presenting, duration: duration) 31 | } 32 | } 33 | 34 | protocol ChildInteractiveTransitionDelegate: class { 35 | func cancelTransition() 36 | func finishTransition() 37 | func updateTransition(percentComplete: CGFloat, direction: ChildInteractiveTransitionDirection, duration: NSTimeInterval?) 38 | } 39 | 40 | class ChildInteractiveTransition: NSObject { 41 | var percentComplete: CGFloat = 0.0 42 | var fromViewController: ChildInteractiveTransitionViewController 43 | var toViewController: ChildInteractiveTransitionViewController 44 | var containerView: UIView 45 | var direction: ChildInteractiveTransitionDirection 46 | weak var delegate: ChildInteractiveTransitionDelegate? 47 | 48 | init(containerView: UIView, fromViewController:ChildInteractiveTransitionViewController, toViewController:ChildInteractiveTransitionViewController, direction:ChildInteractiveTransitionDirection) { 49 | self.containerView = containerView 50 | self.fromViewController = fromViewController 51 | self.toViewController = toViewController 52 | self.direction = direction 53 | switch direction { 54 | case .Left: 55 | toViewController.view.frame = CGRectOffset(toViewController.view.bounds, CGRectGetWidth(toViewController.view.bounds), 0) 56 | case .Right: 57 | toViewController.view.frame = CGRectOffset(toViewController.view.bounds, -CGRectGetWidth(toViewController.view.bounds), 0) 58 | } 59 | 60 | containerView.addSubview(toViewController.view) 61 | 62 | super.init() 63 | } 64 | 65 | func updateInteractiveTransition(percentComplete: CGFloat) { 66 | var toViewFrame: CGRect = self.toViewController.view.bounds 67 | var fromViewFrame: CGRect = self.fromViewController.view.bounds 68 | switch direction { 69 | case .Left: 70 | toViewFrame.origin.x = CGRectGetWidth(toViewFrame)*(1.0 - percentComplete) 71 | fromViewFrame.origin.x = CITParalaxCoefficient*CGRectGetWidth(fromViewFrame)*(-percentComplete) 72 | case .Right: 73 | toViewFrame.origin.x = CGRectGetWidth(toViewFrame)*(percentComplete - 1.0) 74 | fromViewFrame.origin.x = CITParalaxCoefficient*CGRectGetWidth(fromViewFrame)*percentComplete 75 | } 76 | 77 | self.toViewController.view.frame = toViewFrame 78 | self.delegate?.updateTransition(percentComplete, direction: self.direction, duration: nil) 79 | self.toViewController.updateTransition(percentComplete, direction: self.direction, presenting: true, duration: nil) 80 | self.fromViewController.updateTransition(percentComplete, direction: self.direction, presenting: false, duration: nil) 81 | self.percentComplete = percentComplete 82 | } 83 | 84 | func finishInteractiveTransition(#force: Bool) { 85 | var toViewFrame: CGRect = self.toViewController.view.bounds 86 | var fromViewFrame: CGRect = self.fromViewController.view.bounds 87 | if force || self.percentComplete >= CITMinPercentageToFinish { 88 | //finish 89 | switch self.direction { 90 | case .Left: 91 | toViewFrame.origin.x = 0 92 | fromViewFrame.origin.x = -CITParalaxCoefficient*CGRectGetWidth(fromViewFrame) 93 | case .Right: 94 | toViewFrame.origin.x = 0 95 | fromViewFrame.origin.x = CITParalaxCoefficient*CGRectGetWidth(fromViewFrame) 96 | } 97 | 98 | self.delegate?.updateTransition(1.0, direction: self.direction, duration: CITDuration) 99 | self.toViewController.finishTransition(self.direction, presenting: true, duration: CITDuration) 100 | self.fromViewController.finishTransition(self.direction, presenting: false, duration: CITDuration) 101 | UIView.animateWithDuration(CITDuration, animations: { 102 | self.toViewController.view.frame = toViewFrame 103 | }, completion: { finished in 104 | self.delegate?.finishTransition() 105 | }) 106 | } 107 | else { 108 | //cancel 109 | switch self.direction { 110 | case .Left: 111 | toViewFrame.origin.x = CGRectGetWidth(toViewFrame) 112 | fromViewFrame.origin.x = 0 113 | case .Right: 114 | toViewFrame.origin.x = -CGRectGetWidth(toViewFrame) 115 | fromViewFrame.origin.x = 0 116 | } 117 | 118 | self.delegate?.updateTransition(0.0, direction: self.direction, duration: CITDuration) 119 | self.toViewController.cancelTransition(self.direction, presenting: true, duration: CITDuration) 120 | self.fromViewController.cancelTransition(self.direction, presenting: false, duration: CITDuration) 121 | UIView.animateWithDuration(CITDuration, animations: { 122 | self.toViewController.view.frame = toViewFrame 123 | }, completion: { finished in 124 | self.delegate?.cancelTransition() 125 | }) 126 | } 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InteractiveTransitionWithParallax 2 | Simple interactive transitions with parallax in Swift 3 | 4 | ![Presentation](https://cloud.githubusercontent.com/assets/5690240/7442629/59375116-f121-11e4-97f3-d087ed76d4c9.gif) 5 | 6 | ![Presentation](https://cloud.githubusercontent.com/assets/5690240/7442628/58db7c1a-f121-11e4-9cfa-46ab6466bde4.gif) 7 | 8 | 9 | --------------------------------------------------------------------------------