├── .gitignore
├── Configs
├── UIWindowTransitions.plist
└── UIWindowTransitionsTests.plist
├── ExampleApp
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── ViewController.swift
└── ViewController2.swift
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── UIWindowTransitions
│ └── UIWindowTransitions.swift
├── Tests
├── LinuxMain.swift
└── UIWindowTransitionsTests
│ └── UIWindowTransitionsTests.swift
├── UIWindowTransitions.podspec
├── UIWindowTransitions.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── daniele.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcshareddata
│ └── xcschemes
│ │ └── UIWindowTransitions-iOS.xcscheme
└── xcuserdata
│ └── daniele.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── UIWindowTransitions
└── .gitignore
├── UIWindowTransitions_Demo_Animation.gif
└── banner.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | xcshareddata
3 | *.xcuserstate
4 |
--------------------------------------------------------------------------------
/Configs/UIWindowTransitions.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 | 0.1.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 0
23 | NSHumanReadableCopyright
24 | Copyright © 2017 Daniele Margutti. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Configs/UIWindowTransitionsTests.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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ExampleApp/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ExampleApp
4 | //
5 | // Created by danielemargutti on 31/10/2017.
6 | // Copyright © 2017 Daniele Margutti. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ExampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/ExampleApp/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ExampleApp/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
30 |
36 |
47 |
58 |
69 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
149 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
--------------------------------------------------------------------------------
/ExampleApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ExampleApp/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ExampleApp
4 | //
5 | // Created by danielemargutti on 31/10/2017.
6 | // Copyright © 2017 Daniele Margutti. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import UIWindowTransitions
11 |
12 | class ViewController: UIViewController {
13 |
14 | @IBOutlet public var button_top: UIButton?
15 | @IBOutlet public var button_bottom: UIButton?
16 | @IBOutlet public var button_left: UIButton?
17 | @IBOutlet public var button_right: UIButton?
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 | // Do any additional setup after loading the view, typically from a nib.
22 |
23 | [button_top,button_bottom,button_left,button_right].forEach {
24 | $0?.tint()
25 | }
26 | }
27 |
28 | override func didReceiveMemoryWarning() {
29 | super.didReceiveMemoryWarning()
30 | // Dispose of any resources that can be recreated.
31 | }
32 |
33 |
34 | @IBAction func tapButton(_ sender: UIButton) {
35 | let wnd = UIApplication.shared.keyWindow
36 |
37 | let u = UIStoryboard(name: "Main", bundle: Bundle.main)
38 | let vc = u.instantiateViewController(withIdentifier: "Navigation") as! UINavigationController
39 |
40 | let options = UIWindow.TransitionOptions()
41 | switch sender.tag {
42 | case 0:
43 | options.direction = .toRight
44 | case 1:
45 | options.direction = .toLeft
46 | case 2:
47 | options.direction = .toTop
48 | case 3:
49 | options.direction = .toBottom
50 | default:
51 | break
52 | }
53 | wnd?.set(rootViewController: vc, options: options, nil)
54 | }
55 |
56 | }
57 |
58 | public extension UIButton {
59 |
60 | func tint() {
61 | self.layer.borderColor = UIColor.white.cgColor
62 | self.layer.borderWidth = 1.0
63 | self.layer.cornerRadius = 4
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/ExampleApp/ViewController2.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController2.swift
3 | // ExampleApp
4 | //
5 | // Created by danielemargutti on 31/10/2017.
6 | // Copyright © 2017 Daniele Margutti. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public class ViewController2: UIViewController {
13 |
14 | @IBOutlet public var button_reset: UIButton?
15 |
16 | @IBAction func tapButton(_ sender: UIButton) {
17 | let u = UIStoryboard(name: "Main", bundle: Bundle.main)
18 | let vc = u.instantiateViewController(withIdentifier: "ViewController")
19 |
20 | let opt = UIWindow.TransitionOptions(direction: .toLeft, style: .easeInOut)
21 | //opt.background = UIWindow.TransitionOptions.Background.solidColor(UIColor.red)
22 | opt.duration = 0.25
23 | UIApplication.shared.keyWindow?.set(rootViewController: vc, options: opt, nil)
24 | }
25 |
26 | public override func viewDidLoad() {
27 | super.viewDidLoad()
28 | button_reset!.tint()
29 | self.navigationItem.title = "Navigation Bar"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Daniele Margutti
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 |
23 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "UIWindowTransitions",
8 | products: [
9 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
10 | .library(
11 | name: "UIWindowTransitions",
12 | targets: ["UIWindowTransitions"]),
13 | ],
14 | dependencies: [
15 | // Dependencies declare other packages that this package depends on.
16 | // .package(url: /* package url */, from: "1.0.0"),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
21 | .target(
22 | name: "UIWindowTransitions",
23 | dependencies: []),
24 | .testTarget(
25 | name: "UIWindowTransitionsTests",
26 | dependencies: ["UIWindowTransitions"]),
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Animate UIWindow's rootViewController transitions
6 |
7 | This is a small project used to demostrate how to implement UIWindow's `rootViewController` transitions with a little piece of code.
8 | You can found the original article for [this article here](http://danielemargutti.com/animate-uiwindows-rootviewcontroller-transitions).
9 |
10 | ## Motivation
11 |
12 | Sometimes during the lifecycle of an application you may need to change the `rootViewController` of your main `UIWindow` ; a typical case maybe the transition between the initial on-boarding and the home of the app (ie. a `UITabBarController` ).
13 |
14 | In order to handle this edge case you may want to create a top controller (typically an `UINavigationController` with invisible navigation bar) which enable you to push your new container using a standard push animation.
15 |
16 | While basically it works fine, the addition of a container used only to handle this single operation is a bit awful to see.
17 |
18 | A way better solution is to apply an animated transition (push/pop or slide) to the `rootViewController` set so you will get an animate switch from the current view controller to the new one.
19 |
20 | In fact, even if not exposed, you can and its really simple to accomplish via `CoreAnimation` and `CATransition` .
21 |
22 | The following code implements a new function as extension of `UIWindow` class; it takes two arguments: the destination controller and options.
23 |
24 | As you may imagine the destination controller is the controller you want to set as new `rootViewController`, while options is struct used to group some typical CoreAnimation settings: the animation direction (pop/push/slide from top or bottom), the animation curve (linear, ease in/out), the duration of the animation (by default is 0.25s) and an optional UIView instance used to fade in/out between the old and new view.
25 |
26 | ## Known Issue & Fix
27 |
28 | The 1.0.0 fixes and issue with iOS currently opened as [radar here](http://www.openradar.me/21404408). This fix was created by voltbank in his repository [ReplaceRootViewController](https://github.com/voltbank/ReplaceRootViewController) forked from this project.
29 |
30 | ## ❤️ Your Support
31 |
32 | *Hi fellow developer!*
33 | You know, maintaing and developing tools consumes resources and time. While I enjoy making them **your support is foundamental to allow me continue its development**.
34 |
35 | If you are using SwiftLocation or any other of my creations please consider the following options:
36 |
37 | - [**Make a donation with PayPal**](https://www.paypal.com/paypalme/danielemargutti/20)
38 | - [**Become a Sponsor**](https://github.com/sponsors/malcommac)
39 |
40 | - [Follow Me](https://github.com/malcommac)
41 | -
42 | ## How to use it
43 |
44 | Once implemented you can use the only function exposed to all UIWindow instances called
45 | ```swift
46 | func set(rootViewController newRootViewController: UIViewController, options: TransitionOptions = TransitionOptions(), _ completion:((Bool) -> Void)? = nil)
47 | ```
48 |
49 | where:
50 |
51 | * `controller`: the destination view controller to set as new `rootViewController`
52 | * `options`: a `TransitionOptions` with the following properties:
53 | * `duration`: duration of the animation (expressed in `TimeInterval`, seconds, default is `0.25`)
54 | * `direction`: direction of the transition (`toRight`,`toLeft`,`toTop`,`toBottom`, default is `.toRight`)
55 | * `style`: animation curve (`linear`,`easeIn`,`easeOut`,`easeInOut`, default is `.linear`)
56 | * `background`: background view set for fade in-out into the old/new controller (by default is `nil`).
57 | * `completion`: completion callback to receive info when transition did completes.
58 |
59 | The following code change the ``rootViewController`` using a ease out - slide up animation of 0.4 seconds.
60 |
61 | ```swift
62 | let wnd = UIApplication.shared.keyWindow
63 | var options = UIWindow.TransitionOptions()
64 | options.direction = .toTop
65 | options.duration = 0.4
66 | options.style = .easeOut
67 | wnd?.set(rootViewController(newVC, options: options)
68 | ```
69 |
70 | If you just need of a simple push (like `UINavigationController`'s push) you can call it without the `options` arg:
71 |
72 | ```swift
73 | wnd?.set(rootViewController(newVC)
74 | ```
75 |
76 | ## Demo App
77 |
78 | The following demo is available inside the project's demo application.
79 |
80 | 
81 |
82 | ## Installation
83 | You can install UIWindowTransitions using CocoaPods, Carthage and Swift package manager
84 |
85 | `pod 'UIWindowTransitions'`
86 |
87 | ### CocoaPods
88 |
89 | ```ruby
90 | use_frameworks!
91 | pod 'UIWindowTransitions'
92 | ```
93 |
94 | ### Swift Package Manager
95 | Add UIWindowTransitions as dependency in your `Package.swift`
96 |
97 | ```swift
98 | import PackageDescription
99 |
100 | let package = Package(name: "YourPackage",
101 | dependencies: [
102 | .Package(url: "https://github.com/malcommac/UIWindowTransitions.git", majorVersion: 0),
103 | ]
104 | )
105 | ```
106 |
107 | ## Contributing
108 |
109 | - If you **need help** or you'd like to **ask a general question**, open an issue.
110 | - If you **found a bug**, open an issue.
111 | - If you **have a feature request**, open an issue.
112 | - If you **want to contribute**, submit a pull request.
113 |
114 | ## Copyright & Acknowledgements
115 |
116 | UIWindowTransitions is currently owned and maintained by Daniele Margutti.
117 | You can follow me on Twitter [@danielemargutti](http://twitter.com/danielemargutti).
118 | My web site is [https://www.danielemargutti.com](https://www.danielemargutti.com)
119 |
120 | This software is licensed under [MIT License](LICENSE.md).
121 |
122 | ***Follow me on:***
123 | - 💼 [Linkedin](https://www.linkedin.com/in/danielemargutti/)
124 | - 🐦 [Twitter](https://twitter.com/danielemargutti)
--------------------------------------------------------------------------------
/Sources/UIWindowTransitions/UIWindowTransitions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIWindowTransitions.swift
3 | //
4 | // Copyright (c) 2020 Daniele Margutti (hello@danielemargutti.com).
5 | // Additional work by sushant to fix https://stackoverflow.com/a/27153956/8923019
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in
15 | // all copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | // THE SOFTWARE.
24 | //
25 |
26 | import Foundation
27 | import UIKit
28 |
29 | public extension UIWindow {
30 |
31 | /// Transition Options
32 | class TransitionOptions: NSObject, CAAnimationDelegate {
33 |
34 | /// Curve of animation
35 | ///
36 | /// - linear: linear
37 | /// - easeIn: ease in
38 | /// - easeOut: ease out
39 | /// - easeInOut: ease in - ease out
40 | public enum Curve {
41 | case linear
42 | case easeIn
43 | case easeOut
44 | case easeInOut
45 |
46 | /// Return the media timing function associated with curve
47 | internal var function: CAMediaTimingFunction {
48 | let key: String!
49 | switch self {
50 | case .linear: key = convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.linear)
51 | case .easeIn: key = convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.easeIn)
52 | case .easeOut: key = convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.easeOut)
53 | case .easeInOut: key = convertFromCAMediaTimingFunctionName(CAMediaTimingFunctionName.easeInEaseOut)
54 | }
55 | return CAMediaTimingFunction(name: convertToCAMediaTimingFunctionName(key))
56 | }
57 | }
58 |
59 | /// Direction of the animation
60 | ///
61 | /// - fade: fade to new controller
62 | /// - toTop: slide from bottom to top
63 | /// - toBottom: slide from top to bottom
64 | /// - toLeft: pop to left
65 | /// - toRight: push to right
66 | public enum Direction {
67 | case fade
68 | case toTop
69 | case toBottom
70 | case toLeft
71 | case toRight
72 |
73 | /// Return the associated transition
74 | ///
75 | /// - Returns: transition
76 | internal func transition() -> CATransition {
77 | let transition = CATransition()
78 | transition.type = CATransitionType.push
79 | switch self {
80 | case .fade:
81 | transition.type = CATransitionType.fade
82 | transition.subtype = nil
83 | case .toLeft:
84 | transition.subtype = CATransitionSubtype.fromLeft
85 | case .toRight:
86 | transition.subtype = CATransitionSubtype.fromRight
87 | case .toTop:
88 | transition.subtype = CATransitionSubtype.fromTop
89 | case .toBottom:
90 | transition.subtype = CATransitionSubtype.fromBottom
91 | }
92 | return transition
93 | }
94 | }
95 |
96 | /// Background of the transition
97 | /// - snapshot: snapshot of current root view controller
98 | /// - solidColor: solid color
99 | /// - customView: custom view
100 | public enum Background {
101 | case snapshot
102 | case solidColor(_: UIColor)
103 | case customView(_: UIView)
104 | }
105 |
106 | /// Duration of the animation (default is 0.20s)
107 | public var duration: TimeInterval = 0.20
108 |
109 | /// Direction of the transition (default is `toRight`)
110 | public var direction: TransitionOptions.Direction = .toRight
111 |
112 | /// Style of the transition (default is `linear`)
113 | public var style: TransitionOptions.Curve = .linear
114 |
115 | /// Background of the transition (default is `nil`)
116 | public var background: TransitionOptions.Background? = nil
117 |
118 | public var completionBlock: ((Bool) -> Void)? = nil
119 |
120 | weak var previousViewController: UIViewController?
121 |
122 | /// Initialize a new options object with given direction and curve
123 | ///
124 | /// - Parameters:
125 | /// - direction: direction
126 | /// - style: style
127 | public init(direction: TransitionOptions.Direction = .toRight, style: TransitionOptions.Curve = .linear) {
128 | self.direction = direction
129 | self.style = style
130 | }
131 |
132 | /// Return the animation to perform for given options object
133 | internal var animation: CATransition {
134 | let transition = self.direction.transition()
135 | transition.duration = self.duration
136 | transition.timingFunction = self.style.function
137 | transition.delegate = self
138 |
139 | return transition
140 | }
141 |
142 | public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
143 | let oldNavigationController = previousViewController as? UINavigationController
144 | oldNavigationController?.viewControllers = []//This is a tempoarary hack - not sure why nav controllers arent freed up.
145 |
146 | completionBlock?(flag)
147 | }
148 | }
149 |
150 |
151 | /// Fix for http://stackoverflow.com/a/27153956/849645
152 | func set(rootViewController newRootViewController: UIViewController, options: TransitionOptions = TransitionOptions(), _ completion:((Bool) -> Void)? = nil) {
153 |
154 | let previousViewController = rootViewController
155 |
156 | layer.add(options.animation, forKey: kCATransition)
157 | options.completionBlock = completion
158 | options.previousViewController = rootViewController
159 |
160 | rootViewController = newRootViewController
161 |
162 | // Update status bar appearance using the new view controllers appearance - animate if needed
163 | if UIView.areAnimationsEnabled {
164 | UIView.animate(withDuration: CATransaction.animationDuration()) {
165 | newRootViewController.setNeedsStatusBarAppearanceUpdate()
166 | }
167 | } else {
168 | newRootViewController.setNeedsStatusBarAppearanceUpdate()
169 | }
170 |
171 | if #available(iOS 13.0, *) {
172 | // In iOS 13 we don't want to remove the transition view as it'll create a blank screen
173 | } else {
174 | // The presenting view controllers view doesn't get removed from the window as its currently transistioning and presenting a view controller
175 | if let transitionViewClass = NSClassFromString("UITransitionView") {
176 | for subview in subviews where subview.isKind(of: transitionViewClass) {
177 | subview.removeFromSuperview()
178 | }
179 | }
180 | }
181 | if let previousViewController = previousViewController {
182 | // Allow the view controller to be deallocated
183 | previousViewController.dismiss(animated: false) {
184 | // Remove the root view in case its still showing
185 | previousViewController.view.removeFromSuperview()
186 | }
187 | }
188 | }
189 | }
190 |
191 | // Helper function inserted by Swift 4.2 migrator.
192 | fileprivate func convertFromCAMediaTimingFunctionName(_ input: CAMediaTimingFunctionName) -> String {
193 | return input.rawValue
194 | }
195 |
196 | // Helper function inserted by Swift 4.2 migrator.
197 | fileprivate func convertToCAMediaTimingFunctionName(_ input: String) -> CAMediaTimingFunctionName {
198 | return CAMediaTimingFunctionName(rawValue: input)
199 | }
200 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import UIWindowTransitionsTests
3 |
4 | XCTMain([
5 | testCase(UIWindowTransitionsTests.allTests),
6 | ])
7 |
--------------------------------------------------------------------------------
/Tests/UIWindowTransitionsTests/UIWindowTransitionsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIWindowTransitionsTests.swift
3 | // Daniele Margutti
4 | //
5 | // Created by Daniele Margutti on 31/10/2017.
6 | // Copyright © 2017 Daniele Margutti. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import XCTest
11 | import UIWindowTransitions
12 |
13 | class UIWindowTransitionsTests: XCTestCase {
14 | func testExample() {
15 | // This is an example of a functional test case.
16 | // Use XCTAssert and related functions to verify your tests produce the correct results.
17 | //// XCTAssertEqual(UIWindowTransitions().text, "Hello, World!")
18 | }
19 |
20 | static var allTests = [
21 | ("testExample", testExample),
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/UIWindowTransitions.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "UIWindowTransitions"
3 | s.version = "1.0.0"
4 | s.summary = "Animated transitions for UIWindow's rootViewController property"
5 | s.description = <<-DESC
6 | This library allows to execute animated transition when changing the UIWindow's rootViewController property. Animations are done using CoreAnimation.
7 | DESC
8 | s.homepage = "https://github.com/malcommac/UIWindowTransitions"
9 | s.license = { :type => "MIT", :file => "LICENSE" }
10 | s.author = { "Daniele Margutti" => "me@danielemargutti.com" }
11 | s.social_media_url = "https://twitter.com/danielemargutti"
12 | s.ios.deployment_target = "11.0"
13 | s.source = { :git => "https://github.com/malcommac/UIWindowTransitions.git", :tag => s.version.to_s }
14 | s.source_files = "Sources/**/*.swift"
15 | s.frameworks = "Foundation"
16 | s.swift_versions = ['5.0', '5.1', '5.3']
17 | end
18 |
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 47;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 640CE0C51FA857C800CF5222 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640CE0C41FA857C800CF5222 /* AppDelegate.swift */; };
11 | 640CE0C71FA857C800CF5222 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640CE0C61FA857C800CF5222 /* ViewController.swift */; };
12 | 640CE0CA1FA857C800CF5222 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 640CE0C81FA857C800CF5222 /* Main.storyboard */; };
13 | 640CE0CC1FA857C800CF5222 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 640CE0CB1FA857C800CF5222 /* Assets.xcassets */; };
14 | 640CE0CF1FA857C800CF5222 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 640CE0CD1FA857C800CF5222 /* LaunchScreen.storyboard */; };
15 | 640CE0D91FA86D7E00CF5222 /* UIWindowTransitions.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* UIWindowTransitions.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
16 | 640CE0DB1FA87BCF00CF5222 /* ViewController2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640CE0DA1FA87BCF00CF5222 /* ViewController2.swift */; };
17 | 64FB68E81FCAF77C0092C430 /* UIWindowTransitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FB68E71FCAF77C0092C430 /* UIWindowTransitions.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 640CE0D61FA86D5A00CF5222 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205;
26 | remoteInfo = "UIWindowTransitions-iOS";
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXCopyFilesBuildPhase section */
31 | 640CE0D81FA86D7200CF5222 /* Copy Frameworks */ = {
32 | isa = PBXCopyFilesBuildPhase;
33 | buildActionMask = 2147483647;
34 | dstPath = "";
35 | dstSubfolderSpec = 10;
36 | files = (
37 | 640CE0D91FA86D7E00CF5222 /* UIWindowTransitions.framework in Copy Frameworks */,
38 | );
39 | name = "Copy Frameworks";
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXCopyFilesBuildPhase section */
43 |
44 | /* Begin PBXFileReference section */
45 | 52D6D97C1BEFF229002C0205 /* UIWindowTransitions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UIWindowTransitions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
46 | 640CE0C21FA857C800CF5222 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
47 | 640CE0C41FA857C800CF5222 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
48 | 640CE0C61FA857C800CF5222 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
49 | 640CE0C91FA857C800CF5222 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
50 | 640CE0CB1FA857C800CF5222 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
51 | 640CE0CE1FA857C800CF5222 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
52 | 640CE0D01FA857C800CF5222 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | 640CE0DA1FA87BCF00CF5222 /* ViewController2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController2.swift; sourceTree = ""; };
54 | 64FB68E71FCAF77C0092C430 /* UIWindowTransitions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIWindowTransitions.swift; path = UIWindowTransitions/UIWindowTransitions.swift; sourceTree = ""; };
55 | 8933C7891EB5B82A000D00A4 /* UIWindowTransitionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIWindowTransitionsTests.swift; sourceTree = ""; };
56 | AD2FAA261CD0B6D800659CF4 /* UIWindowTransitions.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = UIWindowTransitions.plist; sourceTree = ""; };
57 | AD2FAA281CD0B6E100659CF4 /* UIWindowTransitionsTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = UIWindowTransitionsTests.plist; sourceTree = ""; };
58 | /* End PBXFileReference section */
59 |
60 | /* Begin PBXFrameworksBuildPhase section */
61 | 52D6D9781BEFF229002C0205 /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | 640CE0BF1FA857C800CF5222 /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 52D6D9721BEFF229002C0205 = {
79 | isa = PBXGroup;
80 | children = (
81 | 8933C7811EB5B7E0000D00A4 /* Sources */,
82 | 8933C7831EB5B7EB000D00A4 /* Tests */,
83 | 52D6D99C1BEFF38C002C0205 /* Configs */,
84 | 640CE0C31FA857C800CF5222 /* ExampleApp */,
85 | 52D6D97D1BEFF229002C0205 /* Products */,
86 | );
87 | sourceTree = "";
88 | };
89 | 52D6D97D1BEFF229002C0205 /* Products */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 52D6D97C1BEFF229002C0205 /* UIWindowTransitions.framework */,
93 | 640CE0C21FA857C800CF5222 /* ExampleApp.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 52D6D99C1BEFF38C002C0205 /* Configs */ = {
99 | isa = PBXGroup;
100 | children = (
101 | DD7502721C68FC1B006590AF /* Frameworks */,
102 | DD7502731C68FC20006590AF /* Tests */,
103 | );
104 | path = Configs;
105 | sourceTree = "";
106 | };
107 | 640CE0C31FA857C800CF5222 /* ExampleApp */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 640CE0C41FA857C800CF5222 /* AppDelegate.swift */,
111 | 640CE0C61FA857C800CF5222 /* ViewController.swift */,
112 | 640CE0DA1FA87BCF00CF5222 /* ViewController2.swift */,
113 | 640CE0C81FA857C800CF5222 /* Main.storyboard */,
114 | 640CE0CB1FA857C800CF5222 /* Assets.xcassets */,
115 | 640CE0CD1FA857C800CF5222 /* LaunchScreen.storyboard */,
116 | 640CE0D01FA857C800CF5222 /* Info.plist */,
117 | );
118 | path = ExampleApp;
119 | sourceTree = "";
120 | };
121 | 8933C7811EB5B7E0000D00A4 /* Sources */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 64FB68E71FCAF77C0092C430 /* UIWindowTransitions.swift */,
125 | );
126 | path = Sources;
127 | sourceTree = "";
128 | };
129 | 8933C7831EB5B7EB000D00A4 /* Tests */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 8933C7891EB5B82A000D00A4 /* UIWindowTransitionsTests.swift */,
133 | );
134 | name = Tests;
135 | path = Tests/UIWindowTransitionsTests;
136 | sourceTree = "";
137 | };
138 | DD7502721C68FC1B006590AF /* Frameworks */ = {
139 | isa = PBXGroup;
140 | children = (
141 | AD2FAA261CD0B6D800659CF4 /* UIWindowTransitions.plist */,
142 | );
143 | name = Frameworks;
144 | sourceTree = "";
145 | };
146 | DD7502731C68FC20006590AF /* Tests */ = {
147 | isa = PBXGroup;
148 | children = (
149 | AD2FAA281CD0B6E100659CF4 /* UIWindowTransitionsTests.plist */,
150 | );
151 | name = Tests;
152 | sourceTree = "";
153 | };
154 | /* End PBXGroup section */
155 |
156 | /* Begin PBXHeadersBuildPhase section */
157 | 52D6D9791BEFF229002C0205 /* Headers */ = {
158 | isa = PBXHeadersBuildPhase;
159 | buildActionMask = 2147483647;
160 | files = (
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXHeadersBuildPhase section */
165 |
166 | /* Begin PBXNativeTarget section */
167 | 52D6D97B1BEFF229002C0205 /* UIWindowTransitions-iOS */ = {
168 | isa = PBXNativeTarget;
169 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UIWindowTransitions-iOS" */;
170 | buildPhases = (
171 | 52D6D9771BEFF229002C0205 /* Sources */,
172 | 52D6D9781BEFF229002C0205 /* Frameworks */,
173 | 52D6D9791BEFF229002C0205 /* Headers */,
174 | 52D6D97A1BEFF229002C0205 /* Resources */,
175 | );
176 | buildRules = (
177 | );
178 | dependencies = (
179 | );
180 | name = "UIWindowTransitions-iOS";
181 | productName = UIWindowTransitions;
182 | productReference = 52D6D97C1BEFF229002C0205 /* UIWindowTransitions.framework */;
183 | productType = "com.apple.product-type.framework";
184 | };
185 | 640CE0C11FA857C800CF5222 /* ExampleApp */ = {
186 | isa = PBXNativeTarget;
187 | buildConfigurationList = 640CE0D11FA857C800CF5222 /* Build configuration list for PBXNativeTarget "ExampleApp" */;
188 | buildPhases = (
189 | 640CE0BE1FA857C800CF5222 /* Sources */,
190 | 640CE0BF1FA857C800CF5222 /* Frameworks */,
191 | 640CE0C01FA857C800CF5222 /* Resources */,
192 | 640CE0D81FA86D7200CF5222 /* Copy Frameworks */,
193 | );
194 | buildRules = (
195 | );
196 | dependencies = (
197 | 640CE0D71FA86D5A00CF5222 /* PBXTargetDependency */,
198 | );
199 | name = ExampleApp;
200 | productName = ExampleApp;
201 | productReference = 640CE0C21FA857C800CF5222 /* ExampleApp.app */;
202 | productType = "com.apple.product-type.application";
203 | };
204 | /* End PBXNativeTarget section */
205 |
206 | /* Begin PBXProject section */
207 | 52D6D9731BEFF229002C0205 /* Project object */ = {
208 | isa = PBXProject;
209 | attributes = {
210 | LastSwiftUpdateCheck = 0900;
211 | LastUpgradeCheck = 1220;
212 | ORGANIZATIONNAME = "Daniele Margutti";
213 | TargetAttributes = {
214 | 52D6D97B1BEFF229002C0205 = {
215 | CreatedOnToolsVersion = 7.1;
216 | LastSwiftMigration = 1220;
217 | };
218 | 640CE0C11FA857C800CF5222 = {
219 | CreatedOnToolsVersion = 9.0.1;
220 | DevelopmentTeam = E5DU3FA699;
221 | LastSwiftMigration = 1220;
222 | ProvisioningStyle = Automatic;
223 | };
224 | };
225 | };
226 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "UIWindowTransitions" */;
227 | compatibilityVersion = "Xcode 6.3";
228 | developmentRegion = en;
229 | hasScannedForEncodings = 0;
230 | knownRegions = (
231 | en,
232 | Base,
233 | );
234 | mainGroup = 52D6D9721BEFF229002C0205;
235 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */;
236 | projectDirPath = "";
237 | projectRoot = "";
238 | targets = (
239 | 52D6D97B1BEFF229002C0205 /* UIWindowTransitions-iOS */,
240 | 640CE0C11FA857C800CF5222 /* ExampleApp */,
241 | );
242 | };
243 | /* End PBXProject section */
244 |
245 | /* Begin PBXResourcesBuildPhase section */
246 | 52D6D97A1BEFF229002C0205 /* Resources */ = {
247 | isa = PBXResourcesBuildPhase;
248 | buildActionMask = 2147483647;
249 | files = (
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | 640CE0C01FA857C800CF5222 /* Resources */ = {
254 | isa = PBXResourcesBuildPhase;
255 | buildActionMask = 2147483647;
256 | files = (
257 | 640CE0CF1FA857C800CF5222 /* LaunchScreen.storyboard in Resources */,
258 | 640CE0CC1FA857C800CF5222 /* Assets.xcassets in Resources */,
259 | 640CE0CA1FA857C800CF5222 /* Main.storyboard in Resources */,
260 | );
261 | runOnlyForDeploymentPostprocessing = 0;
262 | };
263 | /* End PBXResourcesBuildPhase section */
264 |
265 | /* Begin PBXSourcesBuildPhase section */
266 | 52D6D9771BEFF229002C0205 /* Sources */ = {
267 | isa = PBXSourcesBuildPhase;
268 | buildActionMask = 2147483647;
269 | files = (
270 | 64FB68E81FCAF77C0092C430 /* UIWindowTransitions.swift in Sources */,
271 | );
272 | runOnlyForDeploymentPostprocessing = 0;
273 | };
274 | 640CE0BE1FA857C800CF5222 /* Sources */ = {
275 | isa = PBXSourcesBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | 640CE0C71FA857C800CF5222 /* ViewController.swift in Sources */,
279 | 640CE0C51FA857C800CF5222 /* AppDelegate.swift in Sources */,
280 | 640CE0DB1FA87BCF00CF5222 /* ViewController2.swift in Sources */,
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | };
284 | /* End PBXSourcesBuildPhase section */
285 |
286 | /* Begin PBXTargetDependency section */
287 | 640CE0D71FA86D5A00CF5222 /* PBXTargetDependency */ = {
288 | isa = PBXTargetDependency;
289 | target = 52D6D97B1BEFF229002C0205 /* UIWindowTransitions-iOS */;
290 | targetProxy = 640CE0D61FA86D5A00CF5222 /* PBXContainerItemProxy */;
291 | };
292 | /* End PBXTargetDependency section */
293 |
294 | /* Begin PBXVariantGroup section */
295 | 640CE0C81FA857C800CF5222 /* Main.storyboard */ = {
296 | isa = PBXVariantGroup;
297 | children = (
298 | 640CE0C91FA857C800CF5222 /* Base */,
299 | );
300 | name = Main.storyboard;
301 | sourceTree = "";
302 | };
303 | 640CE0CD1FA857C800CF5222 /* LaunchScreen.storyboard */ = {
304 | isa = PBXVariantGroup;
305 | children = (
306 | 640CE0CE1FA857C800CF5222 /* Base */,
307 | );
308 | name = LaunchScreen.storyboard;
309 | sourceTree = "";
310 | };
311 | /* End PBXVariantGroup section */
312 |
313 | /* Begin XCBuildConfiguration section */
314 | 52D6D98E1BEFF229002C0205 /* Debug */ = {
315 | isa = XCBuildConfiguration;
316 | buildSettings = {
317 | ALWAYS_SEARCH_USER_PATHS = NO;
318 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
319 | CLANG_CXX_LIBRARY = "libc++";
320 | CLANG_ENABLE_MODULES = YES;
321 | CLANG_ENABLE_OBJC_ARC = YES;
322 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
323 | CLANG_WARN_BOOL_CONVERSION = YES;
324 | CLANG_WARN_COMMA = YES;
325 | CLANG_WARN_CONSTANT_CONVERSION = YES;
326 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
328 | CLANG_WARN_EMPTY_BODY = YES;
329 | CLANG_WARN_ENUM_CONVERSION = YES;
330 | CLANG_WARN_INFINITE_RECURSION = YES;
331 | CLANG_WARN_INT_CONVERSION = YES;
332 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
333 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
334 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
335 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
336 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
337 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
338 | CLANG_WARN_STRICT_PROTOTYPES = YES;
339 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
340 | CLANG_WARN_UNREACHABLE_CODE = YES;
341 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
342 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
343 | COPY_PHASE_STRIP = NO;
344 | CURRENT_PROJECT_VERSION = 1;
345 | DEBUG_INFORMATION_FORMAT = dwarf;
346 | ENABLE_STRICT_OBJC_MSGSEND = YES;
347 | ENABLE_TESTABILITY = YES;
348 | GCC_C_LANGUAGE_STANDARD = gnu99;
349 | GCC_DYNAMIC_NO_PIC = NO;
350 | GCC_NO_COMMON_BLOCKS = YES;
351 | GCC_OPTIMIZATION_LEVEL = 0;
352 | GCC_PREPROCESSOR_DEFINITIONS = (
353 | "DEBUG=1",
354 | "$(inherited)",
355 | );
356 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
357 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
358 | GCC_WARN_UNDECLARED_SELECTOR = YES;
359 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
360 | GCC_WARN_UNUSED_FUNCTION = YES;
361 | GCC_WARN_UNUSED_VARIABLE = YES;
362 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
363 | MTL_ENABLE_DEBUG_INFO = YES;
364 | ONLY_ACTIVE_ARCH = YES;
365 | SDKROOT = iphoneos;
366 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
367 | SWIFT_VERSION = 5.0;
368 | TARGETED_DEVICE_FAMILY = "1,2";
369 | VERSIONING_SYSTEM = "apple-generic";
370 | VERSION_INFO_PREFIX = "";
371 | };
372 | name = Debug;
373 | };
374 | 52D6D98F1BEFF229002C0205 /* Release */ = {
375 | isa = XCBuildConfiguration;
376 | buildSettings = {
377 | ALWAYS_SEARCH_USER_PATHS = NO;
378 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
379 | CLANG_CXX_LIBRARY = "libc++";
380 | CLANG_ENABLE_MODULES = YES;
381 | CLANG_ENABLE_OBJC_ARC = YES;
382 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
383 | CLANG_WARN_BOOL_CONVERSION = YES;
384 | CLANG_WARN_COMMA = YES;
385 | CLANG_WARN_CONSTANT_CONVERSION = YES;
386 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
387 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
388 | CLANG_WARN_EMPTY_BODY = YES;
389 | CLANG_WARN_ENUM_CONVERSION = YES;
390 | CLANG_WARN_INFINITE_RECURSION = YES;
391 | CLANG_WARN_INT_CONVERSION = YES;
392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
396 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
397 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
398 | CLANG_WARN_STRICT_PROTOTYPES = YES;
399 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
400 | CLANG_WARN_UNREACHABLE_CODE = YES;
401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
403 | COPY_PHASE_STRIP = NO;
404 | CURRENT_PROJECT_VERSION = 1;
405 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
406 | ENABLE_NS_ASSERTIONS = NO;
407 | ENABLE_STRICT_OBJC_MSGSEND = YES;
408 | GCC_C_LANGUAGE_STANDARD = gnu99;
409 | GCC_NO_COMMON_BLOCKS = YES;
410 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
411 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
412 | GCC_WARN_UNDECLARED_SELECTOR = YES;
413 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
414 | GCC_WARN_UNUSED_FUNCTION = YES;
415 | GCC_WARN_UNUSED_VARIABLE = YES;
416 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
417 | MTL_ENABLE_DEBUG_INFO = NO;
418 | SDKROOT = iphoneos;
419 | SWIFT_VERSION = 5.0;
420 | TARGETED_DEVICE_FAMILY = "1,2";
421 | VALIDATE_PRODUCT = YES;
422 | VERSIONING_SYSTEM = "apple-generic";
423 | VERSION_INFO_PREFIX = "";
424 | };
425 | name = Release;
426 | };
427 | 52D6D9911BEFF229002C0205 /* Debug */ = {
428 | isa = XCBuildConfiguration;
429 | buildSettings = {
430 | APPLICATION_EXTENSION_API_ONLY = YES;
431 | CLANG_ENABLE_MODULES = YES;
432 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
433 | DEFINES_MODULE = YES;
434 | DYLIB_COMPATIBILITY_VERSION = 1;
435 | DYLIB_CURRENT_VERSION = 1;
436 | DYLIB_INSTALL_NAME_BASE = "@rpath";
437 | INFOPLIST_FILE = Configs/UIWindowTransitions.plist;
438 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
439 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
440 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
441 | ONLY_ACTIVE_ARCH = NO;
442 | PRODUCT_BUNDLE_IDENTIFIER = "com.UIWindowTransitions.UIWindowTransitions-iOS";
443 | PRODUCT_NAME = UIWindowTransitions;
444 | SKIP_INSTALL = YES;
445 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
446 | SWIFT_VERSION = 5.0;
447 | };
448 | name = Debug;
449 | };
450 | 52D6D9921BEFF229002C0205 /* Release */ = {
451 | isa = XCBuildConfiguration;
452 | buildSettings = {
453 | APPLICATION_EXTENSION_API_ONLY = YES;
454 | CLANG_ENABLE_MODULES = YES;
455 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
456 | DEFINES_MODULE = YES;
457 | DYLIB_COMPATIBILITY_VERSION = 1;
458 | DYLIB_CURRENT_VERSION = 1;
459 | DYLIB_INSTALL_NAME_BASE = "@rpath";
460 | INFOPLIST_FILE = Configs/UIWindowTransitions.plist;
461 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
462 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
463 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
464 | PRODUCT_BUNDLE_IDENTIFIER = "com.UIWindowTransitions.UIWindowTransitions-iOS";
465 | PRODUCT_NAME = UIWindowTransitions;
466 | SKIP_INSTALL = YES;
467 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
468 | SWIFT_VERSION = 5.0;
469 | };
470 | name = Release;
471 | };
472 | 640CE0D21FA857C800CF5222 /* Debug */ = {
473 | isa = XCBuildConfiguration;
474 | buildSettings = {
475 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
476 | CLANG_ANALYZER_NONNULL = YES;
477 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
478 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
479 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
480 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
481 | CODE_SIGN_IDENTITY = "iPhone Developer";
482 | CODE_SIGN_STYLE = Automatic;
483 | DEVELOPMENT_TEAM = E5DU3FA699;
484 | GCC_C_LANGUAGE_STANDARD = gnu11;
485 | INFOPLIST_FILE = ExampleApp/Info.plist;
486 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
487 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
488 | PRODUCT_BUNDLE_IDENTIFIER = com.danielemargutti.ExampleApp;
489 | PRODUCT_NAME = "$(TARGET_NAME)";
490 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
491 | SWIFT_VERSION = 5.0;
492 | TARGETED_DEVICE_FAMILY = "1,2";
493 | };
494 | name = Debug;
495 | };
496 | 640CE0D31FA857C800CF5222 /* Release */ = {
497 | isa = XCBuildConfiguration;
498 | buildSettings = {
499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
500 | CLANG_ANALYZER_NONNULL = YES;
501 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
502 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
503 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
504 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
505 | CODE_SIGN_IDENTITY = "iPhone Developer";
506 | CODE_SIGN_STYLE = Automatic;
507 | DEVELOPMENT_TEAM = E5DU3FA699;
508 | GCC_C_LANGUAGE_STANDARD = gnu11;
509 | INFOPLIST_FILE = ExampleApp/Info.plist;
510 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
511 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
512 | PRODUCT_BUNDLE_IDENTIFIER = com.danielemargutti.ExampleApp;
513 | PRODUCT_NAME = "$(TARGET_NAME)";
514 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
515 | SWIFT_VERSION = 5.0;
516 | TARGETED_DEVICE_FAMILY = "1,2";
517 | };
518 | name = Release;
519 | };
520 | /* End XCBuildConfiguration section */
521 |
522 | /* Begin XCConfigurationList section */
523 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "UIWindowTransitions" */ = {
524 | isa = XCConfigurationList;
525 | buildConfigurations = (
526 | 52D6D98E1BEFF229002C0205 /* Debug */,
527 | 52D6D98F1BEFF229002C0205 /* Release */,
528 | );
529 | defaultConfigurationIsVisible = 0;
530 | defaultConfigurationName = Release;
531 | };
532 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "UIWindowTransitions-iOS" */ = {
533 | isa = XCConfigurationList;
534 | buildConfigurations = (
535 | 52D6D9911BEFF229002C0205 /* Debug */,
536 | 52D6D9921BEFF229002C0205 /* Release */,
537 | );
538 | defaultConfigurationIsVisible = 0;
539 | defaultConfigurationName = Release;
540 | };
541 | 640CE0D11FA857C800CF5222 /* Build configuration list for PBXNativeTarget "ExampleApp" */ = {
542 | isa = XCConfigurationList;
543 | buildConfigurations = (
544 | 640CE0D21FA857C800CF5222 /* Debug */,
545 | 640CE0D31FA857C800CF5222 /* Release */,
546 | );
547 | defaultConfigurationIsVisible = 0;
548 | defaultConfigurationName = Release;
549 | };
550 | /* End XCConfigurationList section */
551 | };
552 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */;
553 | }
554 |
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/UIWindowTransitions/9fae35fc44e2742cb12f640afbad6111355bda85/UIWindowTransitions.xcodeproj/project.xcworkspace/xcuserdata/daniele.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/xcshareddata/xcschemes/UIWindowTransitions-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
64 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/xcuserdata/daniele.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/UIWindowTransitions.xcodeproj/xcuserdata/daniele.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ExampleApp.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 | ExampleApp.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 1
16 |
17 | UIWindowTransitions-iOS.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 0
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/UIWindowTransitions/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/UIWindowTransitions_Demo_Animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/UIWindowTransitions/9fae35fc44e2742cb12f640afbad6111355bda85/UIWindowTransitions_Demo_Animation.gif
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/malcommac/UIWindowTransitions/9fae35fc44e2742cb12f640afbad6111355bda85/banner.png
--------------------------------------------------------------------------------