├── imgs
├── animation_example.gif
└── animation_code_example.gif
├── iOS Example
├── Assets.xcassets
│ ├── Contents.json
│ ├── img_logo.imageset
│ │ ├── img_logo.png
│ │ ├── img_logo@2x.png
│ │ ├── img_logo@3x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── SecondViewController.swift
├── UIButton+Extensions.swift
├── FirstViewController.swift
├── Info.plist
├── AlphaByStepTransition.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
├── FashionTransition.swift
└── Main.storyboard
├── AZTransitions.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ └── AZTransitions.xcscheme
└── project.pbxproj
├── .gitignore
├── Source
├── AZTransitions.h
├── Info.plist
└── CustomModalTransition.swift
├── AZTransitions.podspec
├── LICENSE
├── Package.swift
└── README.md
/imgs/animation_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azimin/AZTransitions/HEAD/imgs/animation_example.gif
--------------------------------------------------------------------------------
/imgs/animation_code_example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azimin/AZTransitions/HEAD/imgs/animation_code_example.gif
--------------------------------------------------------------------------------
/iOS Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/iOS Example/Assets.xcassets/img_logo.imageset/img_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azimin/AZTransitions/HEAD/iOS Example/Assets.xcassets/img_logo.imageset/img_logo.png
--------------------------------------------------------------------------------
/iOS Example/Assets.xcassets/img_logo.imageset/img_logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azimin/AZTransitions/HEAD/iOS Example/Assets.xcassets/img_logo.imageset/img_logo@2x.png
--------------------------------------------------------------------------------
/iOS Example/Assets.xcassets/img_logo.imageset/img_logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/azimin/AZTransitions/HEAD/iOS Example/Assets.xcassets/img_logo.imageset/img_logo@3x.png
--------------------------------------------------------------------------------
/AZTransitions.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AZTransitions.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## OS X Finder
2 | .DS_Store
3 |
4 | ## Build generated
5 | build/
6 | DerivedData
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata
18 |
19 | ## Other
20 | *.xccheckout
21 | *.moved-aside
22 | *.xcuserstate
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 |
29 | # Swift Package Manager
30 | .build/
31 |
32 | # Carthage
33 | Carthage/Build
--------------------------------------------------------------------------------
/iOS Example/Assets.xcassets/img_logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "img_logo.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "img_logo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "img_logo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/iOS Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // iOS Example
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | return true
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Source/AZTransitions.h:
--------------------------------------------------------------------------------
1 | //
2 | // AZTransitions.h
3 | // AZTransitions
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for AZTransitions.
12 | FOUNDATION_EXPORT double AZTransitionsVersionNumber;
13 |
14 | //! Project version string for AZTransitions.
15 | FOUNDATION_EXPORT const unsigned char AZTransitionsVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/iOS Example/SecondViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondViewController.swift
3 | // iOS Example
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SecondViewController: UIViewController {
12 |
13 | @IBOutlet weak var closeButton: UIButton! {
14 | didSet {
15 | closeButton.underlineCurrentTitle()
16 | }
17 | }
18 |
19 | @IBAction func closeButtonAction(_ sender: UIButton) {
20 | self.dismiss(animated: true, completion: nil)
21 | }
22 |
23 | override var preferredStatusBarStyle: UIStatusBarStyle {
24 | return .lightContent
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/iOS Example/UIButton+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+Extensions.swift
3 | // AZTransitions
4 | //
5 | // Created by Alex Zimin on 06/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIButton {
12 | func underlineCurrentTitle() {
13 | guard let text = title(for: .normal) else { return }
14 | let textRange = NSMakeRange(0, text.count)
15 | let attributedText = NSMutableAttributedString(string: text)
16 | attributedText.addAttribute(.underlineStyle , value: NSUnderlineStyle.single.rawValue, range: textRange)
17 | attributedText.addAttribute(.foregroundColor, value: titleColor(for: .normal) ?? UIColor.blue, range: textRange)
18 | setAttributedTitle(attributedText, for: .normal)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/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 | 0.26.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/AZTransitions.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "AZTransitions"
3 | s.version = "0.26.0"
4 | s.summary = "Framework that helps you to work with custom modal transtions."
5 | s.description = <<-DESC
6 | With this framework can easily work with custom modal transitions. CustomModalTransition class provides you with all nesessary API, so you should only think about aniamtions.
7 | DESC
8 | s.homepage = "https://github.com/azimin/AZTransition"
9 | s.license = "MIT"
10 | s.author = { "Alexander Zimin" => "azimin@me.com" }
11 |
12 | s.ios.deployment_target = '8.0'
13 | s.source = {
14 | :git => 'https://github.com/azimin/AZTransition.git',
15 | :tag => s.version
16 | }
17 | s.source_files = 'Source/*.swift'
18 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '5' }
19 | end
20 |
--------------------------------------------------------------------------------
/iOS Example/FirstViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstViewController.swift
3 | // iOS Example
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FirstViewController: UIViewController {
12 |
13 | var isOverCurrentContextTransition = false
14 |
15 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
16 | if isOverCurrentContextTransition {
17 | segue.destination.setCustomModalTransition(customModalTransition: AlphaByStepTransition(), inPresentationStyle: .overCurrentContext)
18 | } else {
19 | segue.destination.customModalTransition = FashionTransition()
20 | }
21 | }
22 |
23 | @IBOutlet weak var showButton: UIButton! {
24 | didSet {
25 | showButton.underlineCurrentTitle()
26 | }
27 | }
28 |
29 | @IBAction func isOverTransitionSwiftAction(_ sender: UISwitch) {
30 | isOverCurrentContextTransition = sender.isOn
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/iOS Example/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 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Alex Zimin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
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: "AZTransitions",
8 | platforms: [
9 | .iOS(.v10)
10 | ],
11 | products: [
12 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
13 | .library(
14 | name: "AZTransitions",
15 | targets: ["AZTransitions"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
24 | .target(
25 | name: "AZTransitions",
26 | dependencies: [],
27 | path: "Source"
28 | ),
29 | ]
30 | )
31 |
--------------------------------------------------------------------------------
/iOS Example/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 | 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 | UIInterfaceOrientationPortraitUpsideDown
35 | UIInterfaceOrientationLandscapeLeft
36 | UIInterfaceOrientationLandscapeRight
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/iOS Example/AlphaByStepTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlphaByStepTransition.swift
3 | // AZTransitions
4 | //
5 | // Created by Alex Zimin on 06/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AZTransitions
11 |
12 | private let animationDuration: TimeInterval = 1
13 |
14 | final class AlphaByStepTransition: CustomModalTransition {
15 | override init() {
16 | super.init(duration: animationDuration)
17 | }
18 |
19 | // Ony present
20 | func performTransition(interactive: Bool) {
21 | perfromAnimation()
22 | }
23 |
24 | private func perfromAnimation() {
25 | let halfDuration = duration / 2
26 |
27 | transitionContainerView.bringSubviewToFront(toViewController.view)
28 |
29 | toViewController.view.alpha = 0.0
30 |
31 | UIView.animateKeyframes(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: {
32 | UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: halfDuration, animations: {
33 | self.fromViewController.view.alpha = 0.5
34 | })
35 | UIView.addKeyframe(withRelativeStartTime: halfDuration, relativeDuration: halfDuration, animations: {
36 | self.fromViewController.view.alpha = 1.0
37 | self.toViewController.view.alpha = 0.8
38 | })
39 | }, completion: {
40 | success in
41 | self.finishAnimation(completion: nil)
42 | })
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/iOS Example/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 |
27 |
28 |
--------------------------------------------------------------------------------
/AZTransitions.xcodeproj/xcshareddata/xcschemes/AZTransitions.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/iOS Example/FashionTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FashionTransition.swift
3 | // iOS Example
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AZTransitions
11 |
12 | private let animationDuration: TimeInterval = 1
13 | private let sizeScaleValue: CGFloat = 0.35
14 |
15 | private enum ViewControllerStyle {
16 | case compact
17 | case original
18 | }
19 |
20 | final class FashionTransition: CustomModalTransition {
21 | override init() {
22 | super.init(duration: animationDuration)
23 | }
24 |
25 | func performTransition(interactive: Bool) {
26 | perfromAnimation(isPresenting: true)
27 | }
28 |
29 | func performDismissingTransition(interactive: Bool) {
30 | perfromAnimation(isPresenting: false)
31 | }
32 |
33 | private func perfromAnimation(isPresenting: Bool) {
34 | let halfDuration = duration / 2
35 |
36 | let onScreenViewControllerType: TransitionViewControllerType = isPresenting ? .presenting : .presented
37 | let shouldBeOnScreenViewControllerType: TransitionViewControllerType = isPresenting ? .presented : .presenting
38 |
39 | scale(viewControllerType: onScreenViewControllerType, toStyle: .original)
40 | scale(viewControllerType: shouldBeOnScreenViewControllerType, toStyle: .compact)
41 |
42 | let backgroundView = UIView(frame: transitionContainerView.frame)
43 | backgroundView.backgroundColor = UIColor.black
44 | transitionContainerView.insertSubview(backgroundView, at: 0)
45 |
46 | UIView.animate(withDuration: halfDuration, animations: {
47 | self.scale(viewControllerType: onScreenViewControllerType, toStyle: .compact)
48 | }, completion: {
49 | (completion) in
50 | UIView.animate(withDuration: halfDuration, animations: {
51 | self.scale(viewControllerType: shouldBeOnScreenViewControllerType, toStyle: .original)
52 | }, completion: { (completion) in
53 | backgroundView.removeFromSuperview()
54 | self.finishTransition()
55 | })
56 | })
57 | }
58 |
59 | private var itemCompactWidth: CGFloat {
60 | return self.transitionContainerView.frame.width * sizeScaleValue
61 | }
62 |
63 | private var space: CGFloat {
64 | let coefficent = (1 - sizeScaleValue * 2) / 3
65 | return self.transitionContainerView.frame.width * coefficent
66 | }
67 |
68 | private func scale(viewControllerType: TransitionViewControllerType, toStyle style: ViewControllerStyle) {
69 | let viewController = viewControllerFor(type: viewControllerType)
70 | let anotherViewController = viewControllerFor(type: viewControllerType.revesed)
71 |
72 | let offset: CGFloat = viewControllerType == .presented ? ((space * 2) + itemCompactWidth) : space
73 |
74 | switch style {
75 | case .compact:
76 | scale(viewController: viewController, toValue: sizeScaleValue, withOffset: offset)
77 | default:
78 | transitionContainerView.insertSubview(anotherViewController.view, belowSubview: viewController.view)
79 | scale(viewController: viewController, toValue: 1, withOffset: 0)
80 | }
81 | }
82 |
83 | private func scale(viewController: UIViewController, toValue value: CGFloat, withOffset offset: CGFloat) {
84 | viewController.view.transform = CGAffineTransform(scaleX: value, y: value)
85 | viewController.view.frame.origin.x = offset
86 | }
87 |
88 | private func finishTransition() {
89 | presentingViewController.view.transform = CGAffineTransform.identity
90 | presentedViewController.view.transform = CGAffineTransform.identity
91 | finishAnimation(completion: nil)
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AZTransitions
2 | [](https://img.shields.io/cocoapods/v/AZTransitions.svg)
3 | [](https://github.com/Carthage/Carthage)
4 | [](https://github.com/apple/swift-package-manager)
5 | [](http://cocoadocs.org/docsets/AZTransitions)
6 | [](http://twitter.com/ziminalex)
7 | 
8 |
9 | Make your modal transition with custom animation.
10 | AZTransitions helps you think about creativity, giving specific API methods.
11 |
12 | ## Visual Example
13 |
14 | Inside this repository you can try `iOS Example` target with example `FashionTransition.swift` class:
15 |
16 | 
17 |
18 | ## Installation
19 |
20 | - Add the following to your [`Podfile`](http://cocoapods.org/) and run `pod install`
21 | ```ruby
22 | pod 'AZTransitions'
23 | ```
24 | - or add the following to your [`Cartfile`](https://github.com/Carthage/Carthage) and run `carthage update`
25 | ```
26 | github "azimin/AZTransitions"
27 | ```
28 | - if you are using [`Swift Package Manager`](https://github.com/apple/swift-package-manager) just add it to the `dependencies` value of your `Package.swift`
29 | ```swift
30 | dependencies: [
31 | .package(url: "https://github.com/azimin/AZTransitions.git", .upToNextMajor(from: "0.26.0"))
32 | ]
33 | ```
34 | - or clone as a git submodule,
35 |
36 | - or just copy `AZTransitions/Source/CustomModalTransition.swift` into your project.
37 |
38 | ## Code Example
39 |
40 | To create any custom transition just subclass `CustomModalTransition`:
41 |
42 | ```swift
43 | class FashionTransition: CustomModalTransition {
44 | override init() {
45 | super.init(duration: 0.5)
46 | }
47 | }
48 | ```
49 |
50 | --
51 |
52 | Then set as `az_modalTransition` to nessesary view just before presenting it
53 |
54 | ```swift
55 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
56 | segue.destination.customModalTransition = FashionTransition()
57 | }
58 | ```
59 |
60 | or
61 |
62 | ```swift
63 | func show() {
64 | let viewController = UIViewController()
65 | viewController.customModalTransition = FashionTransition()
66 | self.present(viewController, animated: true, completion: nil)
67 | }
68 | ```
69 |
70 | --
71 |
72 | To have custom present animation, just implement `performTransition(interactive: Bool)` inside your `FashionTransition` class:
73 |
74 | ```swift
75 | func performTransition(interactive: Bool) {
76 | self.presentedViewController.view.alpha = 0.0
77 |
78 | UIView.animate(withDuration: duration, animations: {
79 | self.presentedViewController.view.alpha = 1.0
80 | self.presentingViewController.view.alpha = 0.0
81 | }, completion: { (completed) in
82 | self.presentingViewController.view.alpha = 1.0
83 | self.finishAnimation(completion: nil)
84 | })
85 | }
86 | ```
87 |
88 | As you may have guessed, you have different properties. The main ones:
89 |
90 | - `duration` — transition duration
91 | - `presentingViewController` — the presenting view controller (bottom one)
92 | - `presentedViewController` — view controller that is going to be presented (top one)
93 |
94 | You can animate them as you want.
95 |
96 | **🔥IMPORTANT🔥** don't forget to call `finishAnimation(completion: nil)` in the end.
97 |
98 | In this case animation will be:
99 |
100 | 
101 |
102 | ## UIModalPresentationStyle
103 |
104 | Of course sometimes you want to use diffenret modal presentation styles (for example `overCurrentContext`), in this case you can call `setCustomModalTransition(customModalTransition: CustomModalTransition, inPresentationStyle: UIModalPresentationStyle)` of UIViewController instead of setting `customModalTransition` directly.
105 |
106 | ## More
107 |
108 | You have different properties and methods to help you:
109 |
110 | - `performDismissingTransition(interactive: Bool)` to implement custom transition animation when dismissing
111 | - `fromViewController`/`toViewController` in term of Apple transition. They are reversed in presenting and dismissing transitions.
112 | - `transitionContainerView` view where the transition takes place (`resentingViewController.view` and `presentedViewController.view` located on inside `transitionContainerView`), so you can add your custom views here to make animation more interesting (see `iOS Example`)
113 | - Some methods for interactive animations (example will be added be soon)
114 | - Some method to work with orientation changing things (example will be added be soon)
115 |
--------------------------------------------------------------------------------
/iOS Example/Main.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 |
27 |
28 |
29 |
30 |
40 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/Source/CustomModalTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomModalTransition.swift
3 | // TransitionsHelper
4 | //
5 | // Created by Alex Zimin on 02/11/2016.
6 | // Copyright © 2016 Alexander Zimin. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ObjectiveC.runtime
11 |
12 | @objc
13 | public protocol CustomModalTransitionType: NSObjectProtocol {
14 | @objc optional func performTransition(interactive: Bool)
15 | @objc optional func performDismissingTransition(interactive: Bool)
16 | }
17 |
18 | extension CustomModalTransition: CustomModalTransitionType { }
19 |
20 | public enum TransitionViewControllerType {
21 | case presented
22 | case presenting
23 | case none
24 |
25 | public var revesed: TransitionViewControllerType {
26 | switch self {
27 | case .presented:
28 | return .presenting
29 | case .presenting:
30 | return .presented
31 | case .none:
32 | fatalError("Wrong type")
33 | }
34 | }
35 | }
36 |
37 | open class CustomModalTransition: NSObject {
38 |
39 | // MARK: - Init
40 |
41 | public init(duration: TimeInterval) {
42 | self.duration = duration
43 | }
44 |
45 | public override init() {
46 | self.duration = 0.25
47 | super.init()
48 | }
49 |
50 | // MARK: - Default parametrs
51 |
52 | public private(set) var duration: TimeInterval
53 |
54 | // MARK: - Transition Parameters
55 |
56 | public fileprivate(set) weak var transitionContext: UIViewControllerContextTransitioning!
57 | public fileprivate(set) weak var transitionContainerView: UIView!
58 | public fileprivate(set) var isPresenting: Bool = false
59 | public fileprivate(set) var isInteractive: Bool = false
60 |
61 | // MARK: - View Controllers
62 | // You can choose any pair
63 |
64 | // Presented/preseting style view controllees
65 | public fileprivate(set) weak var presentedViewController: UIViewController!
66 | public fileprivate(set) weak var presentingViewController: UIViewController!
67 |
68 | // Apple style view controllers
69 | public fileprivate(set) weak var fromViewController: UIViewController!
70 | public fileprivate(set) weak var toViewController: UIViewController!
71 |
72 | public func viewControllerFor(type: TransitionViewControllerType) -> UIViewController {
73 | switch type {
74 | case .presented:
75 | return presentedViewController
76 | case .presenting:
77 | return presentingViewController
78 | case .none:
79 | fatalError("Wrong type")
80 | }
81 | }
82 |
83 | public func viewControllerTypeFrom(viewController: UIViewController) -> TransitionViewControllerType {
84 | if viewController == presentedViewController {
85 | return .presented
86 | }
87 | if viewController == presentingViewController {
88 | return .presenting
89 | }
90 | return .none
91 | }
92 |
93 | // MARK: - Animating the Transition
94 |
95 | public func prepareForTransition(isInteractive: Bool) {
96 |
97 | }
98 |
99 | public func finishAnimation(completion: ((_ finished: Bool) -> Void)?) {
100 | let success = !transitionContext.transitionWasCancelled
101 |
102 | completion?(success)
103 |
104 | transitionContext.completeTransition(success)
105 |
106 | self.transitionContext = nil
107 | self.presentingViewController = nil
108 | self.presentedViewController = nil
109 | }
110 |
111 | // MARK: - Interactive Transition
112 |
113 | public func beginInteractiveDismissalTransition(completion: (() -> Void)?) {
114 | self.interactionController = UIPercentDrivenInteractiveTransition()
115 | owningController.dismiss(animated: true, completion: completion)
116 | }
117 |
118 | public func updateInteractiveTransitionToProgress(progress: CGFloat) {
119 | interactionController.update(progress)
120 | }
121 |
122 | public func cancelInteractiveTransition() {
123 | // http://openradar.appspot.com/14675246
124 | interactionController.completionSpeed = 0.999 // http://stackoverflow.com/a/22968139/188461
125 | interactionController.cancel()
126 |
127 | self.interactionController = nil
128 | }
129 |
130 | public func finishInteractiveTransition() {
131 | interactionController.finish()
132 | interactionController = nil
133 | }
134 |
135 | // MARK: - Rotation Helpers
136 |
137 | public private(set) var initialTransform: CGAffineTransform!
138 | public private(set) var finalTransform: CGAffineTransform!
139 |
140 | public func initialCenterFor(viewControllerType: TransitionViewControllerType) -> CGPoint {
141 | let frame = transitionContext.initialFrame(for: viewControllerFor(type: viewControllerType))
142 | return frame.az_center
143 | }
144 |
145 | public func finalCenterFor(viewControllerType: TransitionViewControllerType) -> CGPoint {
146 | let frame = transitionContext.finalFrame(for: viewControllerFor(type: viewControllerType))
147 | return frame.az_center
148 | }
149 |
150 | public func initialBoundsFor(viewControllerType: TransitionViewControllerType) -> CGRect {
151 | let frame = transitionContext.initialFrame(for: viewControllerFor(type: viewControllerType))
152 | let transform = viewControllerType == .presented ? initialTransform : finalTransform
153 | let frameAfterRotation = frame.applying(transform!)
154 | return CGRect(x: 0, y: 0, width: frameAfterRotation.width, height: frameAfterRotation.height)
155 | }
156 |
157 | public func finalBoundsFor(viewControllerType: TransitionViewControllerType) -> CGRect {
158 | let frame = transitionContext.finalFrame(for: viewControllerFor(type: viewControllerType))
159 | let transform = (viewControllerType == .presented) ? initialTransform : finalTransform
160 | let frameAfterRotation = frame.applying(transform!)
161 | return CGRect(x: 0, y: 0, width: frameAfterRotation.width, height: frameAfterRotation.height)
162 | }
163 |
164 | fileprivate func prepareTransitionParameters() {
165 | if isPresenting {
166 | transitionContainerView.addSubview(toViewController.view)
167 | transitionContainerView.addSubview(fromViewController.view)
168 |
169 | self.initialTransform = presentingViewController.view.transform
170 | self.finalTransform = presentedViewController.view.transform
171 |
172 | presentingViewController.view.frame = self.transitionContext.initialFrame(for: presentingViewController)
173 | } else {
174 | transitionContainerView.addSubview(fromViewController.view)
175 | transitionContainerView.addSubview(toViewController.view)
176 |
177 | self.initialTransform = presentedViewController.view.transform;
178 | self.finalTransform = presentingViewController.view.transform;
179 |
180 | presentingViewController.view.frame = self.transitionContext.finalFrame(for: presentingViewController)
181 | }
182 | }
183 |
184 | // MARK: - Private
185 |
186 | fileprivate var interactionController: UIPercentDrivenInteractiveTransition!
187 | fileprivate weak var owningController: UIViewController!
188 | }
189 |
190 | // MARK: - UIViewControllerTransitioningDelegate
191 |
192 | extension CustomModalTransition: UIViewControllerTransitioningDelegate {
193 | public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
194 |
195 | presented.modalPresentationCapturesStatusBarAppearance = true
196 |
197 | // If subclass don't implementing dismissing protocol
198 | if !self.responds(to: #selector(CustomModalTransitionType.performTransition(interactive:))) {
199 | return nil
200 | }
201 |
202 | guard presented == owningController else { return nil }
203 |
204 | self.presentedViewController = presented
205 | self.presentingViewController = presenting
206 | self.isPresenting = true
207 |
208 | return self
209 | }
210 |
211 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
212 |
213 | self.addFinalSetupToDismissedViewController(dismissed: dismissed)
214 |
215 | // If subclass don't implementing dismissing protocol
216 | if !self.responds(to: #selector(CustomModalTransitionType.performDismissingTransition(interactive:))) {
217 | return nil
218 | }
219 |
220 | guard dismissed == owningController else { return nil }
221 |
222 | self.presentedViewController = dismissed
223 | self.presentingViewController = dismissed.presentingViewController
224 | self.isPresenting = false
225 |
226 | return self
227 | }
228 |
229 | // http://openradar.appspot.com/radar?id=5320103646199808
230 | private func addFinalSetupToDismissedViewController(dismissed: UIViewController) {
231 | if dismissed.modalPresentationStyle == .fullScreen || dismissed.modalPresentationStyle == .currentContext {
232 | return
233 | }
234 |
235 | // Adding to main thread queue, becase when this method get called `transitionCoordinator` is nil
236 | OperationQueue.main.addOperation {
237 | dismissed.transitionCoordinator?.animate(alongsideTransition: nil, completion: { (context) in
238 | if !context.isCancelled {
239 | let toViewController = context.viewController(forKey: UITransitionContextViewControllerKey.to)
240 | UIApplication.shared.keyWindow?.addSubview(toViewController!.view)
241 | }
242 | })
243 | }
244 | }
245 |
246 | public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
247 | return interactionController
248 | }
249 | }
250 |
251 | // MARK: - UIViewControllerAnimatedTransitioning
252 |
253 | extension CustomModalTransition: UIViewControllerAnimatedTransitioning {
254 | public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
255 | return duration
256 | }
257 |
258 | public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
259 | self.transitionContext = transitionContext
260 | self.transitionContainerView = transitionContext.containerView
261 | self.isInteractive = transitionContext.isInteractive
262 |
263 | self.fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
264 | self.toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
265 |
266 | prepareTransitionParameters()
267 |
268 | prepareForTransition(isInteractive: isInteractive)
269 |
270 | if isPresenting {
271 | (self as CustomModalTransitionType).performTransition?(interactive: isInteractive)
272 | } else {
273 | (self as CustomModalTransitionType).performDismissingTransition?(interactive: isInteractive)
274 | }
275 | }
276 | }
277 |
278 | // MARK: - UIViewController Extensions
279 |
280 | private var associatedObjectHandle: UInt8 = 0
281 |
282 | public extension UIViewController {
283 | var customModalTransition: CustomModalTransition? {
284 | get {
285 | return objc_getAssociatedObject(self, &associatedObjectHandle) as? CustomModalTransition
286 | }
287 |
288 | set {
289 | self.customModalTransition?.owningController = nil
290 |
291 | self.transitioningDelegate = newValue
292 |
293 | if let transition = newValue {
294 | self.modalPresentationStyle = .fullScreen
295 | transition.owningController = self
296 | }
297 |
298 | objc_setAssociatedObject(self, &associatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
299 | }
300 | }
301 |
302 | func setCustomModalTransition(customModalTransition: CustomModalTransition, inPresentationStyle: UIModalPresentationStyle) {
303 | self.customModalTransition = customModalTransition
304 | self.modalPresentationStyle = inPresentationStyle
305 | }
306 | }
307 |
308 | // MARK: - CGRect Extensions
309 |
310 | private extension CGRect {
311 | var az_center: CGPoint {
312 | return CGPoint(x: self.midX, y: self.midY)
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/AZTransitions.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 921ABFA91DCE8E050085C7F9 /* AlphaByStepTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921ABFA81DCE8E050085C7F9 /* AlphaByStepTransition.swift */; };
11 | 921ABFAE1DCE946D0085C7F9 /* UIButton+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921ABFAD1DCE946D0085C7F9 /* UIButton+Extensions.swift */; };
12 | 921ABFB01DCE94F80085C7F9 /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921ABFAF1DCE94F80085C7F9 /* FirstViewController.swift */; };
13 | 92DE87BF1DCA54B50003D2AB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DE87BE1DCA54B50003D2AB /* AppDelegate.swift */; };
14 | 92DE87C61DCA54B50003D2AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92DE87C51DCA54B50003D2AB /* Assets.xcassets */; };
15 | 92DE87C91DCA54B50003D2AB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92DE87C71DCA54B50003D2AB /* LaunchScreen.storyboard */; };
16 | 92DE87D11DCA54C80003D2AB /* FashionTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DE87D01DCA54C80003D2AB /* FashionTransition.swift */; };
17 | 92DE87D41DCA56DC0003D2AB /* AZTransitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 92DE87D31DCA56DC0003D2AB /* AZTransitions.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | 92DE87D81DCA56E40003D2AB /* CustomModalTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DE87D71DCA56E40003D2AB /* CustomModalTransition.swift */; };
19 | 92DE87DA1DCA57D60003D2AB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92DE87D91DCA57D60003D2AB /* Main.storyboard */; };
20 | 92DE87DE1DCA58370003D2AB /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92DE87DC1DCA58370003D2AB /* SecondViewController.swift */; };
21 | 9F3F74EC1E1687F700382922 /* AZTransitions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92DE87841DCA51300003D2AB /* AZTransitions.framework */; };
22 | 9F3F74ED1E1687F700382922 /* AZTransitions.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 92DE87841DCA51300003D2AB /* AZTransitions.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXContainerItemProxy section */
26 | 92DE87CE1DCA54BC0003D2AB /* PBXContainerItemProxy */ = {
27 | isa = PBXContainerItemProxy;
28 | containerPortal = 92DE877B1DCA51300003D2AB /* Project object */;
29 | proxyType = 1;
30 | remoteGlobalIDString = 92DE87831DCA51300003D2AB;
31 | remoteInfo = AZTransitions;
32 | };
33 | /* End PBXContainerItemProxy section */
34 |
35 | /* Begin PBXCopyFilesBuildPhase section */
36 | 9F3F74EE1E1687F700382922 /* Embed Frameworks */ = {
37 | isa = PBXCopyFilesBuildPhase;
38 | buildActionMask = 2147483647;
39 | dstPath = "";
40 | dstSubfolderSpec = 10;
41 | files = (
42 | 9F3F74ED1E1687F700382922 /* AZTransitions.framework in Embed Frameworks */,
43 | );
44 | name = "Embed Frameworks";
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXCopyFilesBuildPhase section */
48 |
49 | /* Begin PBXFileReference section */
50 | 921ABFA81DCE8E050085C7F9 /* AlphaByStepTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlphaByStepTransition.swift; sourceTree = ""; };
51 | 921ABFAD1DCE946D0085C7F9 /* UIButton+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Extensions.swift"; sourceTree = ""; };
52 | 921ABFAF1DCE94F80085C7F9 /* FirstViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; };
53 | 92DE87841DCA51300003D2AB /* AZTransitions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AZTransitions.framework; sourceTree = BUILT_PRODUCTS_DIR; };
54 | 92DE87BC1DCA54B50003D2AB /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
55 | 92DE87BE1DCA54B50003D2AB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
56 | 92DE87C51DCA54B50003D2AB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
57 | 92DE87C81DCA54B50003D2AB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
58 | 92DE87CA1DCA54B50003D2AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
59 | 92DE87D01DCA54C80003D2AB /* FashionTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FashionTransition.swift; sourceTree = ""; };
60 | 92DE87D31DCA56DC0003D2AB /* AZTransitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AZTransitions.h; path = Source/AZTransitions.h; sourceTree = ""; };
61 | 92DE87D51DCA56E00003D2AB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Source/Info.plist; sourceTree = ""; };
62 | 92DE87D71DCA56E40003D2AB /* CustomModalTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomModalTransition.swift; path = Source/CustomModalTransition.swift; sourceTree = ""; };
63 | 92DE87D91DCA57D60003D2AB /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; };
64 | 92DE87DC1DCA58370003D2AB /* SecondViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; };
65 | /* End PBXFileReference section */
66 |
67 | /* Begin PBXFrameworksBuildPhase section */
68 | 92DE87801DCA51300003D2AB /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | 92DE87B91DCA54B50003D2AB /* Frameworks */ = {
76 | isa = PBXFrameworksBuildPhase;
77 | buildActionMask = 2147483647;
78 | files = (
79 | 9F3F74EC1E1687F700382922 /* AZTransitions.framework in Frameworks */,
80 | );
81 | runOnlyForDeploymentPostprocessing = 0;
82 | };
83 | /* End PBXFrameworksBuildPhase section */
84 |
85 | /* Begin PBXGroup section */
86 | 921ABFAA1DCE944F0085C7F9 /* Transitions */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 92DE87D01DCA54C80003D2AB /* FashionTransition.swift */,
90 | 921ABFA81DCE8E050085C7F9 /* AlphaByStepTransition.swift */,
91 | );
92 | name = Transitions;
93 | sourceTree = "";
94 | };
95 | 921ABFAB1DCE94540085C7F9 /* ViewControllers */ = {
96 | isa = PBXGroup;
97 | children = (
98 | 921ABFAF1DCE94F80085C7F9 /* FirstViewController.swift */,
99 | 92DE87DC1DCA58370003D2AB /* SecondViewController.swift */,
100 | );
101 | name = ViewControllers;
102 | sourceTree = "";
103 | };
104 | 921ABFAC1DCE945B0085C7F9 /* Extensison */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 921ABFAD1DCE946D0085C7F9 /* UIButton+Extensions.swift */,
108 | );
109 | name = Extensison;
110 | sourceTree = "";
111 | };
112 | 92DE877A1DCA51300003D2AB = {
113 | isa = PBXGroup;
114 | children = (
115 | 92DE87D21DCA56CB0003D2AB /* Source */,
116 | 92DE87BD1DCA54B50003D2AB /* iOS Example */,
117 | 92DE87851DCA51300003D2AB /* Products */,
118 | );
119 | sourceTree = "";
120 | };
121 | 92DE87851DCA51300003D2AB /* Products */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 92DE87841DCA51300003D2AB /* AZTransitions.framework */,
125 | 92DE87BC1DCA54B50003D2AB /* iOS Example.app */,
126 | );
127 | name = Products;
128 | sourceTree = "";
129 | };
130 | 92DE87BD1DCA54B50003D2AB /* iOS Example */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 92DE87BE1DCA54B50003D2AB /* AppDelegate.swift */,
134 | 921ABFAB1DCE94540085C7F9 /* ViewControllers */,
135 | 921ABFAA1DCE944F0085C7F9 /* Transitions */,
136 | 921ABFAC1DCE945B0085C7F9 /* Extensison */,
137 | 92DE87D91DCA57D60003D2AB /* Main.storyboard */,
138 | 92DE87C51DCA54B50003D2AB /* Assets.xcassets */,
139 | 92DE87C71DCA54B50003D2AB /* LaunchScreen.storyboard */,
140 | 92DE87CA1DCA54B50003D2AB /* Info.plist */,
141 | );
142 | path = "iOS Example";
143 | sourceTree = "";
144 | };
145 | 92DE87D21DCA56CB0003D2AB /* Source */ = {
146 | isa = PBXGroup;
147 | children = (
148 | 92DE87D31DCA56DC0003D2AB /* AZTransitions.h */,
149 | 92DE87D71DCA56E40003D2AB /* CustomModalTransition.swift */,
150 | 92DE87D51DCA56E00003D2AB /* Info.plist */,
151 | );
152 | name = Source;
153 | sourceTree = "";
154 | };
155 | /* End PBXGroup section */
156 |
157 | /* Begin PBXHeadersBuildPhase section */
158 | 92DE87811DCA51300003D2AB /* Headers */ = {
159 | isa = PBXHeadersBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 92DE87D41DCA56DC0003D2AB /* AZTransitions.h in Headers */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXHeadersBuildPhase section */
167 |
168 | /* Begin PBXNativeTarget section */
169 | 92DE87831DCA51300003D2AB /* AZTransitions */ = {
170 | isa = PBXNativeTarget;
171 | buildConfigurationList = 92DE878C1DCA51300003D2AB /* Build configuration list for PBXNativeTarget "AZTransitions" */;
172 | buildPhases = (
173 | 92DE877F1DCA51300003D2AB /* Sources */,
174 | 92DE87801DCA51300003D2AB /* Frameworks */,
175 | 92DE87811DCA51300003D2AB /* Headers */,
176 | 92DE87821DCA51300003D2AB /* Resources */,
177 | );
178 | buildRules = (
179 | );
180 | dependencies = (
181 | );
182 | name = AZTransitions;
183 | productName = AZTransitions;
184 | productReference = 92DE87841DCA51300003D2AB /* AZTransitions.framework */;
185 | productType = "com.apple.product-type.framework";
186 | };
187 | 92DE87BB1DCA54B50003D2AB /* iOS Example */ = {
188 | isa = PBXNativeTarget;
189 | buildConfigurationList = 92DE87CB1DCA54B50003D2AB /* Build configuration list for PBXNativeTarget "iOS Example" */;
190 | buildPhases = (
191 | 92DE87B81DCA54B50003D2AB /* Sources */,
192 | 92DE87B91DCA54B50003D2AB /* Frameworks */,
193 | 92DE87BA1DCA54B50003D2AB /* Resources */,
194 | 9F3F74EE1E1687F700382922 /* Embed Frameworks */,
195 | );
196 | buildRules = (
197 | );
198 | dependencies = (
199 | 92DE87CF1DCA54BC0003D2AB /* PBXTargetDependency */,
200 | );
201 | name = "iOS Example";
202 | productName = "iOS Example";
203 | productReference = 92DE87BC1DCA54B50003D2AB /* iOS Example.app */;
204 | productType = "com.apple.product-type.application";
205 | };
206 | /* End PBXNativeTarget section */
207 |
208 | /* Begin PBXProject section */
209 | 92DE877B1DCA51300003D2AB /* Project object */ = {
210 | isa = PBXProject;
211 | attributes = {
212 | LastSwiftUpdateCheck = 0810;
213 | LastUpgradeCheck = 1010;
214 | ORGANIZATIONNAME = "Alexander Zimin";
215 | TargetAttributes = {
216 | 92DE87831DCA51300003D2AB = {
217 | CreatedOnToolsVersion = 8.1;
218 | DevelopmentTeam = 5MGEMLZRS4;
219 | LastSwiftMigration = 1020;
220 | ProvisioningStyle = Automatic;
221 | };
222 | 92DE87BB1DCA54B50003D2AB = {
223 | CreatedOnToolsVersion = 8.1;
224 | DevelopmentTeam = 5MGEMLZRS4;
225 | LastSwiftMigration = 1020;
226 | ProvisioningStyle = Automatic;
227 | };
228 | };
229 | };
230 | buildConfigurationList = 92DE877E1DCA51300003D2AB /* Build configuration list for PBXProject "AZTransitions" */;
231 | compatibilityVersion = "Xcode 3.2";
232 | developmentRegion = en;
233 | hasScannedForEncodings = 0;
234 | knownRegions = (
235 | en,
236 | Base,
237 | );
238 | mainGroup = 92DE877A1DCA51300003D2AB;
239 | productRefGroup = 92DE87851DCA51300003D2AB /* Products */;
240 | projectDirPath = "";
241 | projectRoot = "";
242 | targets = (
243 | 92DE87831DCA51300003D2AB /* AZTransitions */,
244 | 92DE87BB1DCA54B50003D2AB /* iOS Example */,
245 | );
246 | };
247 | /* End PBXProject section */
248 |
249 | /* Begin PBXResourcesBuildPhase section */
250 | 92DE87821DCA51300003D2AB /* Resources */ = {
251 | isa = PBXResourcesBuildPhase;
252 | buildActionMask = 2147483647;
253 | files = (
254 | );
255 | runOnlyForDeploymentPostprocessing = 0;
256 | };
257 | 92DE87BA1DCA54B50003D2AB /* Resources */ = {
258 | isa = PBXResourcesBuildPhase;
259 | buildActionMask = 2147483647;
260 | files = (
261 | 92DE87DA1DCA57D60003D2AB /* Main.storyboard in Resources */,
262 | 92DE87C91DCA54B50003D2AB /* LaunchScreen.storyboard in Resources */,
263 | 92DE87C61DCA54B50003D2AB /* Assets.xcassets in Resources */,
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | };
267 | /* End PBXResourcesBuildPhase section */
268 |
269 | /* Begin PBXSourcesBuildPhase section */
270 | 92DE877F1DCA51300003D2AB /* Sources */ = {
271 | isa = PBXSourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | 92DE87D81DCA56E40003D2AB /* CustomModalTransition.swift in Sources */,
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | 92DE87B81DCA54B50003D2AB /* Sources */ = {
279 | isa = PBXSourcesBuildPhase;
280 | buildActionMask = 2147483647;
281 | files = (
282 | 921ABFA91DCE8E050085C7F9 /* AlphaByStepTransition.swift in Sources */,
283 | 921ABFAE1DCE946D0085C7F9 /* UIButton+Extensions.swift in Sources */,
284 | 92DE87D11DCA54C80003D2AB /* FashionTransition.swift in Sources */,
285 | 921ABFB01DCE94F80085C7F9 /* FirstViewController.swift in Sources */,
286 | 92DE87DE1DCA58370003D2AB /* SecondViewController.swift in Sources */,
287 | 92DE87BF1DCA54B50003D2AB /* AppDelegate.swift in Sources */,
288 | );
289 | runOnlyForDeploymentPostprocessing = 0;
290 | };
291 | /* End PBXSourcesBuildPhase section */
292 |
293 | /* Begin PBXTargetDependency section */
294 | 92DE87CF1DCA54BC0003D2AB /* PBXTargetDependency */ = {
295 | isa = PBXTargetDependency;
296 | target = 92DE87831DCA51300003D2AB /* AZTransitions */;
297 | targetProxy = 92DE87CE1DCA54BC0003D2AB /* PBXContainerItemProxy */;
298 | };
299 | /* End PBXTargetDependency section */
300 |
301 | /* Begin PBXVariantGroup section */
302 | 92DE87C71DCA54B50003D2AB /* LaunchScreen.storyboard */ = {
303 | isa = PBXVariantGroup;
304 | children = (
305 | 92DE87C81DCA54B50003D2AB /* Base */,
306 | );
307 | name = LaunchScreen.storyboard;
308 | sourceTree = "";
309 | };
310 | /* End PBXVariantGroup section */
311 |
312 | /* Begin XCBuildConfiguration section */
313 | 92DE878A1DCA51300003D2AB /* Debug */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ALWAYS_SEARCH_USER_PATHS = NO;
317 | CLANG_ANALYZER_NONNULL = YES;
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_DOCUMENTATION_COMMENTS = YES;
329 | CLANG_WARN_EMPTY_BODY = YES;
330 | CLANG_WARN_ENUM_CONVERSION = YES;
331 | CLANG_WARN_INFINITE_RECURSION = YES;
332 | CLANG_WARN_INT_CONVERSION = YES;
333 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
334 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
335 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
337 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
338 | CLANG_WARN_STRICT_PROTOTYPES = YES;
339 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
340 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
341 | CLANG_WARN_UNREACHABLE_CODE = YES;
342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
343 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
344 | COPY_PHASE_STRIP = NO;
345 | CURRENT_PROJECT_VERSION = 1;
346 | DEBUG_INFORMATION_FORMAT = dwarf;
347 | ENABLE_STRICT_OBJC_MSGSEND = YES;
348 | ENABLE_TESTABILITY = YES;
349 | GCC_C_LANGUAGE_STANDARD = gnu99;
350 | GCC_DYNAMIC_NO_PIC = NO;
351 | GCC_NO_COMMON_BLOCKS = YES;
352 | GCC_OPTIMIZATION_LEVEL = 0;
353 | GCC_PREPROCESSOR_DEFINITIONS = (
354 | "DEBUG=1",
355 | "$(inherited)",
356 | );
357 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
358 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
359 | GCC_WARN_UNDECLARED_SELECTOR = YES;
360 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
361 | GCC_WARN_UNUSED_FUNCTION = YES;
362 | GCC_WARN_UNUSED_VARIABLE = YES;
363 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
364 | MTL_ENABLE_DEBUG_INFO = YES;
365 | ONLY_ACTIVE_ARCH = YES;
366 | SDKROOT = iphoneos;
367 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
368 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
369 | TARGETED_DEVICE_FAMILY = "1,2";
370 | VERSIONING_SYSTEM = "apple-generic";
371 | VERSION_INFO_PREFIX = "";
372 | };
373 | name = Debug;
374 | };
375 | 92DE878B1DCA51300003D2AB /* Release */ = {
376 | isa = XCBuildConfiguration;
377 | buildSettings = {
378 | ALWAYS_SEARCH_USER_PATHS = NO;
379 | CLANG_ANALYZER_NONNULL = YES;
380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
381 | CLANG_CXX_LIBRARY = "libc++";
382 | CLANG_ENABLE_MODULES = YES;
383 | CLANG_ENABLE_OBJC_ARC = YES;
384 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
385 | CLANG_WARN_BOOL_CONVERSION = YES;
386 | CLANG_WARN_COMMA = YES;
387 | CLANG_WARN_CONSTANT_CONVERSION = YES;
388 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
390 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
391 | CLANG_WARN_EMPTY_BODY = YES;
392 | CLANG_WARN_ENUM_CONVERSION = YES;
393 | CLANG_WARN_INFINITE_RECURSION = YES;
394 | CLANG_WARN_INT_CONVERSION = YES;
395 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
396 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
397 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
398 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
399 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
400 | CLANG_WARN_STRICT_PROTOTYPES = YES;
401 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
402 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
403 | CLANG_WARN_UNREACHABLE_CODE = YES;
404 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
405 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
406 | COPY_PHASE_STRIP = NO;
407 | CURRENT_PROJECT_VERSION = 1;
408 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
409 | ENABLE_NS_ASSERTIONS = NO;
410 | ENABLE_STRICT_OBJC_MSGSEND = YES;
411 | GCC_C_LANGUAGE_STANDARD = gnu99;
412 | GCC_NO_COMMON_BLOCKS = YES;
413 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
414 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
415 | GCC_WARN_UNDECLARED_SELECTOR = YES;
416 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
417 | GCC_WARN_UNUSED_FUNCTION = YES;
418 | GCC_WARN_UNUSED_VARIABLE = YES;
419 | IPHONEOS_DEPLOYMENT_TARGET = 10.1;
420 | MTL_ENABLE_DEBUG_INFO = NO;
421 | SDKROOT = iphoneos;
422 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
423 | TARGETED_DEVICE_FAMILY = "1,2";
424 | VALIDATE_PRODUCT = YES;
425 | VERSIONING_SYSTEM = "apple-generic";
426 | VERSION_INFO_PREFIX = "";
427 | };
428 | name = Release;
429 | };
430 | 92DE878D1DCA51300003D2AB /* Debug */ = {
431 | isa = XCBuildConfiguration;
432 | buildSettings = {
433 | CLANG_ENABLE_MODULES = YES;
434 | CODE_SIGN_IDENTITY = "";
435 | DEFINES_MODULE = YES;
436 | DEVELOPMENT_TEAM = 5MGEMLZRS4;
437 | DYLIB_COMPATIBILITY_VERSION = 1;
438 | DYLIB_CURRENT_VERSION = 1;
439 | DYLIB_INSTALL_NAME_BASE = "@rpath";
440 | INFOPLIST_FILE = Source/Info.plist;
441 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
442 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
443 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
444 | PRODUCT_BUNDLE_IDENTIFIER = com.alex.AZTransitions;
445 | PRODUCT_NAME = "$(TARGET_NAME)";
446 | SKIP_INSTALL = YES;
447 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
448 | SWIFT_VERSION = 5.0;
449 | };
450 | name = Debug;
451 | };
452 | 92DE878E1DCA51300003D2AB /* Release */ = {
453 | isa = XCBuildConfiguration;
454 | buildSettings = {
455 | CLANG_ENABLE_MODULES = YES;
456 | CODE_SIGN_IDENTITY = "";
457 | DEFINES_MODULE = YES;
458 | DEVELOPMENT_TEAM = 5MGEMLZRS4;
459 | DYLIB_COMPATIBILITY_VERSION = 1;
460 | DYLIB_CURRENT_VERSION = 1;
461 | DYLIB_INSTALL_NAME_BASE = "@rpath";
462 | INFOPLIST_FILE = Source/Info.plist;
463 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
464 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
466 | PRODUCT_BUNDLE_IDENTIFIER = com.alex.AZTransitions;
467 | PRODUCT_NAME = "$(TARGET_NAME)";
468 | SKIP_INSTALL = YES;
469 | SWIFT_VERSION = 5.0;
470 | };
471 | name = Release;
472 | };
473 | 92DE87CC1DCA54B50003D2AB /* Debug */ = {
474 | isa = XCBuildConfiguration;
475 | buildSettings = {
476 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
477 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
478 | DEVELOPMENT_TEAM = 5MGEMLZRS4;
479 | INFOPLIST_FILE = "iOS Example/Info.plist";
480 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
482 | PRODUCT_BUNDLE_IDENTIFIER = "com.alex.iOS-Example";
483 | PRODUCT_NAME = "$(TARGET_NAME)";
484 | SWIFT_VERSION = 5.0;
485 | TARGETED_DEVICE_FAMILY = "1,2";
486 | };
487 | name = Debug;
488 | };
489 | 92DE87CD1DCA54B50003D2AB /* Release */ = {
490 | isa = XCBuildConfiguration;
491 | buildSettings = {
492 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
493 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
494 | DEVELOPMENT_TEAM = 5MGEMLZRS4;
495 | INFOPLIST_FILE = "iOS Example/Info.plist";
496 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
497 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
498 | PRODUCT_BUNDLE_IDENTIFIER = "com.alex.iOS-Example";
499 | PRODUCT_NAME = "$(TARGET_NAME)";
500 | SWIFT_VERSION = 5.0;
501 | TARGETED_DEVICE_FAMILY = "1,2";
502 | };
503 | name = Release;
504 | };
505 | /* End XCBuildConfiguration section */
506 |
507 | /* Begin XCConfigurationList section */
508 | 92DE877E1DCA51300003D2AB /* Build configuration list for PBXProject "AZTransitions" */ = {
509 | isa = XCConfigurationList;
510 | buildConfigurations = (
511 | 92DE878A1DCA51300003D2AB /* Debug */,
512 | 92DE878B1DCA51300003D2AB /* Release */,
513 | );
514 | defaultConfigurationIsVisible = 0;
515 | defaultConfigurationName = Release;
516 | };
517 | 92DE878C1DCA51300003D2AB /* Build configuration list for PBXNativeTarget "AZTransitions" */ = {
518 | isa = XCConfigurationList;
519 | buildConfigurations = (
520 | 92DE878D1DCA51300003D2AB /* Debug */,
521 | 92DE878E1DCA51300003D2AB /* Release */,
522 | );
523 | defaultConfigurationIsVisible = 0;
524 | defaultConfigurationName = Release;
525 | };
526 | 92DE87CB1DCA54B50003D2AB /* Build configuration list for PBXNativeTarget "iOS Example" */ = {
527 | isa = XCConfigurationList;
528 | buildConfigurations = (
529 | 92DE87CC1DCA54B50003D2AB /* Debug */,
530 | 92DE87CD1DCA54B50003D2AB /* Release */,
531 | );
532 | defaultConfigurationIsVisible = 0;
533 | defaultConfigurationName = Release;
534 | };
535 | /* End XCConfigurationList section */
536 | };
537 | rootObject = 92DE877B1DCA51300003D2AB /* Project object */;
538 | }
539 |
--------------------------------------------------------------------------------