├── .gitattributes
├── CustomTransitions
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── ipad152.png
│ │ ├── ipad76.png
│ │ ├── iphone120.png
│ │ ├── iphone180.png
│ │ ├── appstore1024.png
│ │ ├── ipadPro167.png
│ │ ├── iphone120-1.png
│ │ ├── settings58.png
│ │ ├── settings87.png
│ │ ├── ipadSettings29.png
│ │ ├── ipadSettings58.png
│ │ ├── notification60.png
│ │ ├── ipadSpotlight40-1.png
│ │ ├── ipadSpotlight40.png
│ │ ├── ipadSpotlight80-1.png
│ │ ├── ipadSpotlight80.png
│ │ ├── ipadNotification20.png
│ │ ├── ipadNotification40.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── UIColor+Extension.swift
├── UIButton+Extension.swift
├── SceneDelegate.swift
├── Transitions
│ ├── Fancy
│ │ ├── FancyPresentationController.swift
│ │ ├── FancyTransitionManager.swift
│ │ └── FancyTransitionAnimator.swift
│ ├── Slide
│ │ ├── SlideTransitionManager.swift
│ │ └── SlideTransitionAnimator.swift
│ ├── ActionSheet
│ │ ├── ActionSheetTransitionManager.swift
│ │ └── ActionSheetPresentationController.swift
│ └── Alert
│ │ ├── AlertTransitionManager.swift
│ │ ├── AlertTransitionAnimator.swift
│ │ └── AlertPresentationController.swift
├── AppDelegate.swift
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Info.plist
├── DetailViewController.swift
└── HomeViewController.swift
├── CustomTransitions.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── ondrejkorol.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── ondrejkorol.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipad152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipad152.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipad76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipad76.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone120.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone180.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/appstore1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/appstore1024.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadPro167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadPro167.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone120-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/iphone120-1.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/settings58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/settings58.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/settings87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/settings87.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/notification60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/notification60.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40-1.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80-1.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/xcuserdata/ondrejkorol.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/project.xcworkspace/xcuserdata/ondrejkorol.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingondrej/Transitions/HEAD/CustomTransitions.xcodeproj/project.xcworkspace/xcuserdata/ondrejkorol.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CustomTransitions/UIColor+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Extension.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIColor {
11 | static let appBlack = UIColor(red: 0.07, green: 0.08, blue: 0.09, alpha: 1.00)
12 | static let appRed = UIColor(red: 0.87, green: 0.20, blue: 0.24, alpha: 1.00)
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/CustomTransitions/UIButton+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton+Extension.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIButton {
11 | static func appButton() -> UIButton {
12 | let button = UIButton(type: .system)
13 | button.titleLabel?.font = UIFont.systemFont(ofSize: 20, weight: .bold)
14 | button.tintColor = .appRed
15 | return button
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/xcuserdata/ondrejkorol.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | CustomTransitions.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/CustomTransitions/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // PresentAlert
4 | //
5 | // Created by Ondřej Korol on 20.06.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
11 |
12 | var window: UIWindow?
13 |
14 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
15 | guard let windowScene = (scene as? UIWindowScene) else {
16 | return
17 | }
18 |
19 | let viewController = HomeViewController()
20 | window = UIWindow(windowScene: windowScene)
21 | window?.rootViewController = viewController
22 | window?.makeKeyAndVisible()
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Fancy/FancyPresentationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FancyPresentationController.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class FancyPresentationController: UIPresentationController {
11 | // MARK: Presentation
12 | /**
13 | If false is returned from `shouldRemovePresentersView`, the view associated with UITransitionContext.view(forKey: from) is nil during presentation. This intended to be a hint that your animator should NOT be manipulating the presenting view controller's view. For a dismissal, the presentedView is returned.
14 | */
15 | override var shouldRemovePresentersView: Bool {
16 | return true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Slide/SlideTransitionManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SlideTransitionManager.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class SlideTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
11 |
12 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
13 | return SlideTransitionAnimator()
14 | }
15 |
16 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
17 | return nil
18 | }
19 |
20 | func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
21 | return nil
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CustomTransitions/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | @main
11 | class AppDelegate: UIResponder, UIApplicationDelegate {
12 |
13 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
14 | // Override point for customization after application launch.
15 | return true
16 | }
17 |
18 | // MARK: UISceneSession Lifecycle
19 |
20 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
21 | // Called when a new scene session is being created.
22 | // Use this method to select a configuration to create the new scene with.
23 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/ActionSheet/ActionSheetTransitionManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActionSheetTransitionManager.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class ActionSheetTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
11 |
12 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
13 | return nil
14 | }
15 |
16 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
17 | return nil
18 | }
19 |
20 | func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
21 | return ActionSheetPresentationController(
22 | presentedViewController: presented,
23 | presenting: presenting
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Alert/AlertTransitionManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertTransitionManager.swift
3 | // PresentAlert
4 | //
5 | // Created by Ondřej Korol on 20.06.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class AlertTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
11 |
12 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
13 | return AlertTransitionAnimator(transition: .presenting)
14 | }
15 |
16 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
17 | return AlertTransitionAnimator(transition: .dismissing)
18 | }
19 |
20 | func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
21 | return AlertPresentationController(
22 | presentedViewController: presented,
23 | presenting: presenting
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Fancy/FancyTransitionManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FancyTransitionManager.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class FancyTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
11 |
12 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
13 | return FancyTransitionAnimator(transition: .presenting)
14 | }
15 |
16 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
17 | return FancyTransitionAnimator(transition: .dismissing)
18 | }
19 |
20 | func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
21 | return FancyPresentationController(
22 | presentedViewController: presented,
23 | presenting: presenting
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Transitions
4 | A simple iOS app with one default and four custom transitions.
5 | The app uses the same two view controllers for every transition.
6 |
7 | ## Slide
8 | The presented view controller slides in from the right with little overshoot. It uses the default animation provided by UIKit for its dismissal.
9 |
10 | ## Action Sheet
11 | The presented view controller slides in from the bottom with the default animation provided by UIKit.
12 |
13 | Along with the transition, the background (presenting view controller) is dimmed by the blurred view.
14 |
15 | The view controller can be dismissed by tap on the dimmed view or by pulling it down. It uses the default animation provided by UIKit for its dismissal.
16 |
17 | ## Alert
18 | The presented view controller appears in the center by enlarging and fading in.
19 |
20 | Along with the transition, the background (presenting view controller) is dimmed with the blurred view.
21 |
22 | The view controller disappears by shrinking and fading out.
23 |
24 | ## Fancy
25 | The presented view controller fades in while the selected button of the presenting view controller moves across the screen to the position of the presented view controller's title label. Other elements fades out.
26 |
27 |
28 |
29 | 
30 |
31 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Slide/SlideTransitionAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SlideTransitionAnimator.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SlideTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
11 |
12 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
13 | return 1.25
14 | }
15 |
16 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
17 | // 1. Get the view of the presented view controller
18 | guard let toView = transitionContext.view(forKey: .to) else {
19 | transitionContext.completeTransition(false)
20 | return
21 | }
22 |
23 | // 2. Add the view to the transition's container view
24 | let containerView = transitionContext.containerView
25 | containerView.addSubview(toView)
26 |
27 | // 3. Prepare the view for an animation
28 | toView.layoutIfNeeded()
29 | toView.transform = CGAffineTransform(translationX: toView.bounds.width, y: .zero)
30 |
31 | // 4. Perform the actual animation
32 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.50, initialSpringVelocity: 0, animations: {
33 | toView.transform = .identity
34 | }) { _ in
35 | // 5. Tell UIKit that the transition should end
36 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CustomTransitions/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 |
--------------------------------------------------------------------------------
/CustomTransitions/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Transitions
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIApplicationSceneManifest
26 |
27 | UIApplicationSupportsMultipleScenes
28 |
29 | UISceneConfigurations
30 |
31 | UIWindowSceneSessionRoleApplication
32 |
33 |
34 | UISceneConfigurationName
35 | Default Configuration
36 | UISceneDelegateClassName
37 | $(PRODUCT_MODULE_NAME).SceneDelegate
38 |
39 |
40 |
41 |
42 | UIApplicationSupportsIndirectInputEvents
43 |
44 | UILaunchStoryboardName
45 | LaunchScreen
46 | UIRequiredDeviceCapabilities
47 |
48 | armv7
49 |
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationLandscapeLeft
54 | UIInterfaceOrientationLandscapeRight
55 |
56 | UISupportedInterfaceOrientations~ipad
57 |
58 | UIInterfaceOrientationPortrait
59 | UIInterfaceOrientationPortraitUpsideDown
60 | UIInterfaceOrientationLandscapeLeft
61 | UIInterfaceOrientationLandscapeRight
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Alert/AlertTransitionAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertTransitionAnimator.swift
3 | // PresentAlert
4 | //
5 | // Created by Ondřej Korol on 20.06.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class AlertTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
11 | enum Transition {
12 | case presenting
13 | case dismissing
14 |
15 | var duration: TimeInterval {
16 | switch self {
17 | case .presenting:
18 | return 0.3
19 | case .dismissing:
20 | return 0.2
21 | }
22 | }
23 | }
24 |
25 | private static let scaleTransform = CGAffineTransform(scaleX: 0.8, y: 0.8)
26 |
27 | let transition: Transition
28 |
29 | // MARK: Initialization
30 | init(transition: Transition) {
31 | self.transition = transition
32 | }
33 |
34 | // MARK: UIViewControllerAnimatedTransitioning
35 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
36 | transition.duration
37 | }
38 |
39 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
40 | let key: UITransitionContextViewKey = transition == .presenting ? .to : .from
41 |
42 | guard let viewToAnimate = transitionContext.view(forKey: key) else {
43 | transitionContext.completeTransition(false)
44 | return
45 | }
46 |
47 | switch transition {
48 | case .presenting:
49 | let containerView = transitionContext.containerView
50 | containerView.addSubview(viewToAnimate)
51 |
52 | viewToAnimate.alpha = 0
53 | viewToAnimate.transform = Self.scaleTransform
54 |
55 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0) {
56 | viewToAnimate.alpha = 1
57 | viewToAnimate.transform = .identity
58 | } completion: { _ in
59 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
60 | }
61 |
62 | case .dismissing:
63 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 0, animations: {
64 | viewToAnimate.alpha = 0
65 | viewToAnimate.transform = Self.scaleTransform
66 | }) { _ in
67 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/CustomTransitions/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ipadSpotlight40.png",
5 | "idiom" : "iphone",
6 | "scale" : "2x",
7 | "size" : "20x20"
8 | },
9 | {
10 | "filename" : "notification60.png",
11 | "idiom" : "iphone",
12 | "scale" : "3x",
13 | "size" : "20x20"
14 | },
15 | {
16 | "filename" : "settings58.png",
17 | "idiom" : "iphone",
18 | "scale" : "2x",
19 | "size" : "29x29"
20 | },
21 | {
22 | "filename" : "settings87.png",
23 | "idiom" : "iphone",
24 | "scale" : "3x",
25 | "size" : "29x29"
26 | },
27 | {
28 | "filename" : "ipadSpotlight80.png",
29 | "idiom" : "iphone",
30 | "scale" : "2x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "iphone120-1.png",
35 | "idiom" : "iphone",
36 | "scale" : "3x",
37 | "size" : "40x40"
38 | },
39 | {
40 | "filename" : "iphone120.png",
41 | "idiom" : "iphone",
42 | "scale" : "2x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "filename" : "iphone180.png",
47 | "idiom" : "iphone",
48 | "scale" : "3x",
49 | "size" : "60x60"
50 | },
51 | {
52 | "filename" : "ipadNotification20.png",
53 | "idiom" : "ipad",
54 | "scale" : "1x",
55 | "size" : "20x20"
56 | },
57 | {
58 | "filename" : "ipadNotification40.png",
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "20x20"
62 | },
63 | {
64 | "filename" : "ipadSettings29.png",
65 | "idiom" : "ipad",
66 | "scale" : "1x",
67 | "size" : "29x29"
68 | },
69 | {
70 | "filename" : "ipadSettings58.png",
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "29x29"
74 | },
75 | {
76 | "filename" : "ipadSpotlight40-1.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "40x40"
80 | },
81 | {
82 | "filename" : "ipadSpotlight80-1.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "40x40"
86 | },
87 | {
88 | "filename" : "ipad76.png",
89 | "idiom" : "ipad",
90 | "scale" : "1x",
91 | "size" : "76x76"
92 | },
93 | {
94 | "filename" : "ipad152.png",
95 | "idiom" : "ipad",
96 | "scale" : "2x",
97 | "size" : "76x76"
98 | },
99 | {
100 | "filename" : "ipadPro167.png",
101 | "idiom" : "ipad",
102 | "scale" : "2x",
103 | "size" : "83.5x83.5"
104 | },
105 | {
106 | "filename" : "appstore1024.png",
107 | "idiom" : "ios-marketing",
108 | "scale" : "1x",
109 | "size" : "1024x1024"
110 | }
111 | ],
112 | "info" : {
113 | "author" : "xcode",
114 | "version" : 1
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/CustomTransitions/DetailViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DetailViewController.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class DetailViewController: UIViewController {
11 |
12 | // MARK: Views
13 | lazy var titleLabel: UILabel = {
14 | let label = UILabel()
15 | label.textColor = .white
16 | label.textAlignment = .center
17 | label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
18 | label.text = title
19 | return label
20 | }()
21 |
22 | lazy var textLabel: UILabel = {
23 | let label = UILabel()
24 | label.textColor = .white
25 | label.textAlignment = .center
26 | label.numberOfLines = 0
27 | label.font = UIFont.systemFont(ofSize: 17, weight: .medium)
28 | label.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
29 | return label
30 | }()
31 |
32 | lazy var dismissButton: UIButton = {
33 | let button = UIButton.appButton()
34 | button.setTitle("Dismiss", for: .normal)
35 | button.addTarget(self, action: #selector(didTapDismiss), for: .touchUpInside)
36 | return button
37 | }()
38 |
39 | override func viewDidLoad() {
40 | super.viewDidLoad()
41 |
42 | view.backgroundColor = .appBlack
43 |
44 | // Subviews
45 | [titleLabel, textLabel, dismissButton].forEach {
46 | view.addSubview($0)
47 | $0.translatesAutoresizingMaskIntoConstraints = false
48 | }
49 |
50 | titleLabel.setContentHuggingPriority(.required, for: .vertical)
51 |
52 | let inset: CGFloat = 24
53 | NSLayoutConstraint.activate([
54 | titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
55 | titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: inset),
56 | titleLabel.bottomAnchor.constraint(equalTo: textLabel.topAnchor, constant: -inset),
57 |
58 | textLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: inset),
59 | textLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -inset),
60 | textLabel.bottomAnchor.constraint(equalTo: dismissButton.topAnchor, constant: -inset),
61 |
62 | dismissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
63 | dismissButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -inset),
64 | ])
65 | }
66 |
67 | @objc private func didTapDismiss() {
68 | dismiss(animated: true)
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Alert/AlertPresentationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertPresentationController.swift
3 | // PresentAlert
4 | //
5 | // Created by Ondřej Korol on 20.06.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class AlertPresentationController: UIPresentationController {
11 |
12 | // MARK: Constants
13 | private static let alertCornerRadius: CGFloat = 30
14 | private static let alertHorizontalInset: CGFloat = 24
15 | private static let dimmingViewMaxAlpha: CGFloat = 1.0
16 |
17 | // MARK: Views
18 | private lazy var dimmingView: UIView = {
19 | let blurEffect = UIBlurEffect(style: .systemMaterialDark)
20 | let view = UIVisualEffectView(effect: blurEffect)
21 | return view
22 | }()
23 |
24 | // MARK: Presentation
25 | override var frameOfPresentedViewInContainerView: CGRect {
26 | guard
27 | let containerView = containerView,
28 | let presentedView = presentedView
29 | else {
30 | return .zero
31 | }
32 |
33 | let safeAreaFrame = containerView.safeAreaLayoutGuide.layoutFrame
34 |
35 | let targetWidth = safeAreaFrame.width - 2 * Self.alertHorizontalInset
36 | let fittingSize = CGSize(
37 | width: targetWidth,
38 | height: UIView.layoutFittingCompressedSize.height
39 | )
40 |
41 | let targetHeight = presentedView.systemLayoutSizeFitting(
42 | fittingSize,
43 | withHorizontalFittingPriority: .required,
44 | verticalFittingPriority: .defaultLow
45 | ).height
46 |
47 | return CGRect(
48 | x: containerView.center.x - targetWidth / 2,
49 | y: containerView.center.y - targetHeight / 2,
50 | width: targetWidth,
51 | height: targetHeight
52 | )
53 | }
54 |
55 | override func containerViewWillLayoutSubviews() {
56 | super.containerViewWillLayoutSubviews()
57 |
58 | presentedViewController.view.setNeedsLayout()
59 | presentedViewController.view.layoutIfNeeded()
60 | presentedView?.frame = frameOfPresentedViewInContainerView
61 |
62 | dimmingView.frame = containerView?.bounds ?? .zero
63 | }
64 |
65 | override func presentationTransitionWillBegin() {
66 | super.presentationTransitionWillBegin()
67 | guard
68 | let containerView = containerView,
69 | let coordinator = presentingViewController.transitionCoordinator
70 | else {
71 | return
72 | }
73 |
74 | presentedView?.layer.cornerRadius = Self.alertCornerRadius
75 |
76 | dimmingView.frame = containerView.bounds
77 | dimmingView.alpha = 0
78 | containerView.addSubview(dimmingView)
79 |
80 | coordinator.animate(
81 | alongsideTransition: { _ -> Void in
82 | self.dimmingView.alpha = Self.dimmingViewMaxAlpha
83 | },
84 | completion: nil
85 | )
86 | }
87 |
88 | override func dismissalTransitionWillBegin() {
89 | super.dismissalTransitionWillBegin()
90 | guard let coordinator = presentingViewController.transitionCoordinator else {
91 | return
92 | }
93 |
94 | coordinator.animate(
95 | alongsideTransition: { _ -> Void in
96 | self.dimmingView.alpha = 0
97 | },
98 | completion: nil
99 | )
100 | }
101 |
102 | override func dismissalTransitionDidEnd(_ completed: Bool) {
103 | super.dismissalTransitionDidEnd(completed)
104 | if completed {
105 | dimmingView.removeFromSuperview()
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/Fancy/FancyTransitionAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FancyTransitionAnimator.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class FancyTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
11 | enum Transition {
12 | case presenting
13 | case dismissing
14 |
15 | var duration: TimeInterval {
16 | return 1.5
17 | }
18 | }
19 |
20 | let transition: Transition
21 |
22 | // MARK: Initialization
23 | init(transition: Transition) {
24 | self.transition = transition
25 | }
26 |
27 | // MARK: UIViewControllerAnimatedTransitioning
28 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
29 | transition.duration
30 | }
31 |
32 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
33 | guard
34 | let fromViewController = transitionContext.viewController(forKey: .from),
35 | let toViewController = transitionContext.viewController(forKey: .to),
36 | let fromView = transitionContext.view(forKey: .from),
37 | let toView = transitionContext.view(forKey: .to)
38 | else {
39 | transitionContext.completeTransition(false)
40 | return
41 | }
42 |
43 | let containerView = transitionContext.containerView
44 | let fromColor = fromView.backgroundColor
45 | let toColor = toView.backgroundColor
46 |
47 | // Helper container view
48 | let colorView = UIView()
49 | colorView.alpha = 0
50 | colorView.backgroundColor = fromColor
51 | colorView.frame = fromView.frame
52 | containerView.addSubview(colorView)
53 |
54 | // Destination View
55 | containerView.addSubview(toView)
56 | toView.layoutIfNeeded()
57 | toView.alpha = 0
58 |
59 | // Helper label
60 | let fakeLabel = UILabel()
61 |
62 | let fromLabel = transition == .presenting ?
63 | (fromViewController as? HomeViewController)?.fancyButton.titleLabel :
64 | (fromViewController as? DetailViewController)?.titleLabel
65 |
66 | if let fromLabel = fromLabel {
67 | fakeLabel.text = fromLabel.text
68 | fakeLabel.font = fromLabel.font
69 | fakeLabel.textColor = fromLabel.textColor
70 | colorView.addSubview(fakeLabel)
71 | fakeLabel.frame = fromLabel.convert(fromLabel.bounds, to: nil)
72 | }
73 |
74 | let toLabel = transition == .presenting ?
75 | (toViewController as? DetailViewController)?.titleLabel :
76 | (toViewController as? HomeViewController)?.fancyButton.titleLabel
77 |
78 | var fakeLabelFinalRect: CGRect = .zero
79 | if let toLabel = toLabel {
80 | fakeLabelFinalRect = toLabel.convert(toLabel.bounds, to: nil)
81 | }
82 |
83 | UIView.animateKeyframes(withDuration: transitionDuration(using: transitionContext), delay: 0, animations: {
84 | UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.25) {
85 | colorView.alpha = 1
86 | }
87 |
88 | UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.50) {
89 | colorView.backgroundColor = toColor
90 | fakeLabel.frame = fakeLabelFinalRect
91 | }
92 |
93 | UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {
94 | toView.alpha = 1
95 | }
96 | }) { _ in
97 | // Remove helper view
98 | colorView.removeFromSuperview()
99 |
100 | // Notifies the system that the transition animation is done
101 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/CustomTransitions/HomeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeViewController.swift
3 | // PresentAlert
4 | //
5 | // Created by Ondřej Korol on 20.06.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class HomeViewController: UIViewController {
11 |
12 | // MARK: Views
13 | private lazy var stackView: UIStackView = {
14 | let stackView = UIStackView()
15 | stackView.axis = .vertical
16 | stackView.spacing = 24
17 | return stackView
18 | }()
19 |
20 | private lazy var defaultButton: UIButton = {
21 | let button = UIButton.appButton()
22 | button.setTitle("Default", for: .normal)
23 | button.addTarget(self, action: #selector(didTapDefault), for: .touchUpInside)
24 | return button
25 | }()
26 |
27 | private lazy var slideButton: UIButton = {
28 | let button = UIButton.appButton()
29 | button.setTitle("Slide", for: .normal)
30 | button.addTarget(self, action: #selector(didTapSlide), for: .touchUpInside)
31 | return button
32 | }()
33 |
34 | private lazy var actionSheetButton: UIButton = {
35 | let button = UIButton.appButton()
36 | button.setTitle("Action Sheet", for: .normal)
37 | button.addTarget(self, action: #selector(didTapActionSheet), for: .touchUpInside)
38 | return button
39 | }()
40 |
41 | private lazy var alertButton: UIButton = {
42 | let button = UIButton.appButton()
43 | button.setTitle("Alert", for: .normal)
44 | button.addTarget(self, action: #selector(didTapAlert), for: .touchUpInside)
45 | return button
46 | }()
47 |
48 | lazy var fancyButton: UIButton = {
49 | let button = UIButton.appButton()
50 | button.setTitle("Fancy", for: .normal)
51 | button.addTarget(self, action: #selector(didTapFancy), for: .touchUpInside)
52 | return button
53 | }()
54 |
55 | // MARK: Transitions
56 | let slideTransitionManager = SlideTransitionManager()
57 | let actionSheetTransitionManager = ActionSheetTransitionManager()
58 | let alertTransitionManager = AlertTransitionManager()
59 | let fancyTransitionManager = FancyTransitionManager()
60 |
61 | // MARK: Lifecycle
62 | override func viewDidLoad() {
63 | super.viewDidLoad()
64 |
65 | view.backgroundColor = .white
66 |
67 | view.addSubview(stackView)
68 | stackView.translatesAutoresizingMaskIntoConstraints = false
69 | NSLayoutConstraint.activate([
70 | stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
71 | stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
72 | ])
73 |
74 | [defaultButton, slideButton, actionSheetButton, alertButton, fancyButton].forEach {
75 | stackView.addArrangedSubview($0)
76 | }
77 | }
78 | }
79 |
80 | // MARK: - Private actions
81 | private extension HomeViewController {
82 | @objc func didTapDefault(_ sender: UIButton) {
83 | let detailViewController = DetailViewController()
84 | detailViewController.title = sender.currentTitle
85 |
86 | present(detailViewController, animated: true)
87 | }
88 |
89 | @objc func didTapSlide(_ sender: UIButton) {
90 | let detailViewController = DetailViewController()
91 | detailViewController.title = sender.currentTitle
92 |
93 | detailViewController.modalPresentationStyle = .custom
94 | detailViewController.transitioningDelegate = slideTransitionManager
95 |
96 | present(detailViewController, animated: true)
97 | }
98 |
99 | @objc func didTapActionSheet(_ sender: UIButton) {
100 | let detailViewController = DetailViewController()
101 | detailViewController.title = sender.currentTitle
102 |
103 | detailViewController.modalPresentationStyle = .custom
104 | detailViewController.transitioningDelegate = actionSheetTransitionManager
105 |
106 | present(detailViewController, animated: true)
107 | }
108 |
109 | @objc func didTapAlert(_ sender: UIButton) {
110 | let detailViewController = DetailViewController()
111 | detailViewController.title = sender.currentTitle
112 |
113 | detailViewController.modalPresentationStyle = .custom
114 | detailViewController.transitioningDelegate = alertTransitionManager
115 |
116 | present(detailViewController, animated: true)
117 | }
118 |
119 | @objc func didTapFancy(_ sender: UIButton) {
120 | let detailViewController = DetailViewController()
121 | detailViewController.title = sender.currentTitle
122 |
123 | detailViewController.modalPresentationStyle = .custom
124 | detailViewController.transitioningDelegate = fancyTransitionManager
125 |
126 | present(detailViewController, animated: true)
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/CustomTransitions/Transitions/ActionSheet/ActionSheetPresentationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActionSheetPresentationController.swift
3 | // CustomTransitions
4 | //
5 | // Created by Ondřej Korol on 25.07.2021.
6 | //
7 |
8 | import UIKit
9 |
10 | final class ActionSheetPresentationController: UIPresentationController {
11 |
12 | // MARK: Constants
13 | private static let actionSheetCornerRadius: CGFloat = 30
14 | private static let dimmingViewMaxAlpha: CGFloat = 1.0
15 |
16 | // MARK: Views
17 | private lazy var dimmingView: UIView = {
18 | let blurEffect = UIBlurEffect(style: .systemMaterialDark)
19 | let view = UIVisualEffectView(effect: blurEffect)
20 | return view
21 | }()
22 |
23 | // MARK: Gesture Recognizers
24 | private let tapGestureRecognizer = UITapGestureRecognizer()
25 | private let panGestureRecognizer = UIPanGestureRecognizer()
26 |
27 | // MARK: Initialization
28 | override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
29 | super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
30 | configureGestureRecognizers()
31 | }
32 |
33 | // MARK: Presentation
34 | override var frameOfPresentedViewInContainerView: CGRect {
35 | guard let containerView = containerView else {
36 | return .zero
37 | }
38 |
39 | let targetWidth = containerView.bounds.width
40 | let targetHeight = containerView.bounds.height * 0.6
41 |
42 | let originX: CGFloat = .zero
43 | let originY: CGFloat = containerView.bounds.height - targetHeight
44 |
45 | return CGRect(
46 | x: originX,
47 | y: originY,
48 | width: targetWidth,
49 | height: targetHeight
50 | )
51 | }
52 |
53 | override func containerViewWillLayoutSubviews() {
54 | super.containerViewWillLayoutSubviews()
55 | presentedView?.frame = frameOfPresentedViewInContainerView
56 | dimmingView.frame = containerView?.bounds ?? .zero
57 | }
58 |
59 | override func presentationTransitionWillBegin() {
60 | super.presentationTransitionWillBegin()
61 | guard
62 | let containerView = containerView,
63 | let coordinator = presentingViewController.transitionCoordinator
64 | else {
65 | return
66 | }
67 |
68 | presentedView?.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
69 | presentedView?.layer.cornerRadius = Self.actionSheetCornerRadius
70 |
71 | dimmingView.frame = containerView.bounds
72 | dimmingView.alpha = 0
73 | containerView.addSubview(dimmingView)
74 |
75 | coordinator.animate(
76 | alongsideTransition: { _ -> Void in
77 | self.dimmingView.alpha = Self.dimmingViewMaxAlpha
78 | },
79 | completion: nil
80 | )
81 | }
82 |
83 | override func dismissalTransitionWillBegin() {
84 | super.dismissalTransitionWillBegin()
85 | guard let coordinator = presentingViewController.transitionCoordinator else {
86 | return
87 | }
88 |
89 | coordinator.animate(
90 | alongsideTransition: { _ -> Void in
91 | self.dimmingView.alpha = 0
92 | },
93 | completion: nil
94 | )
95 | }
96 |
97 | override func dismissalTransitionDidEnd(_ completed: Bool) {
98 | super.dismissalTransitionDidEnd(completed)
99 | if completed {
100 | dimmingView.removeFromSuperview()
101 | }
102 | }
103 | }
104 |
105 | // MARK: - Private methods
106 | private extension ActionSheetPresentationController {
107 | func configureGestureRecognizers() {
108 | tapGestureRecognizer.addTarget(self, action: #selector(handleTap))
109 | dimmingView.addGestureRecognizer(tapGestureRecognizer)
110 |
111 | panGestureRecognizer.addTarget(self, action: #selector(handlePan))
112 | presentedView?.addGestureRecognizer(panGestureRecognizer)
113 | }
114 |
115 | @objc func handleTap(sender: UITapGestureRecognizer) {
116 | presentedViewController.dismiss(animated: true)
117 | }
118 |
119 | @objc func handlePan(sender: UIPanGestureRecognizer) {
120 | switch sender.state {
121 | case .changed:
122 | guard
123 | let presentedView = presentedView
124 | else {
125 | return
126 | }
127 |
128 | let translationY = sender.translation(in: presentedView).y
129 | let originY = frameOfPresentedViewInContainerView.minY
130 | let updatedOriginY = originY + translationY
131 |
132 | // Update position
133 | presentedView.frame.origin.y = max(updatedOriginY, originY)
134 |
135 | // Update alpha
136 | if updatedOriginY >= originY {
137 | dimmingView.alpha = (1 - (translationY / presentedView.bounds.height)) * Self.dimmingViewMaxAlpha
138 | }
139 |
140 | // Workaround for inconsistent view layout during transition.
141 | // Adjusting safe area because safe area disappears when frame is changed.
142 | presentedViewController.additionalSafeAreaInsets.bottom = updatedOriginY > originY ?
143 | containerView?.safeAreaInsets.bottom ?? 0 :
144 | 0.0
145 | case .ended:
146 | guard let presentedView = presentedView else {
147 | return
148 | }
149 |
150 | let velocityY = sender.velocity(in: presentedView).y
151 | let originY = frameOfPresentedViewInContainerView.minY
152 | let viewHeight = presentedView.frame.height
153 |
154 | // Dismiss only if the gesture is in the correct direction
155 | let directionCheck = velocityY > 0
156 |
157 | // Dismiss only if more than 40% of modal is hidden or there is a significant velocity
158 | let distanceCheck = presentedView.frame.origin.y > originY + (viewHeight * 0.4)
159 | let velocityCheck = velocityY > 500
160 |
161 | if directionCheck, distanceCheck || velocityCheck {
162 | presentedViewController.dismiss(animated: true)
163 | } else {
164 | UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut) {
165 | self.presentedView?.frame.origin.y = originY
166 | self.dimmingView.alpha = Self.dimmingViewMaxAlpha
167 | self.presentedViewController.additionalSafeAreaInsets.bottom = 0
168 | }
169 | }
170 | default:
171 | break
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/CustomTransitions.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 773E7C4A26AD6B1800AC1A8A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C4926AD6B1800AC1A8A /* AppDelegate.swift */; };
11 | 773E7C4C26AD6B1800AC1A8A /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C4B26AD6B1800AC1A8A /* SceneDelegate.swift */; };
12 | 773E7C4E26AD6B1800AC1A8A /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C4D26AD6B1800AC1A8A /* HomeViewController.swift */; };
13 | 773E7C5326AD6B1A00AC1A8A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 773E7C5226AD6B1A00AC1A8A /* Assets.xcassets */; };
14 | 773E7C5626AD6B1A00AC1A8A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 773E7C5426AD6B1A00AC1A8A /* LaunchScreen.storyboard */; };
15 | 773E7C6326AD6B7100AC1A8A /* AlertTransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C5F26AD6B7100AC1A8A /* AlertTransitionAnimator.swift */; };
16 | 773E7C6426AD6B7100AC1A8A /* AlertTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6026AD6B7100AC1A8A /* AlertTransitionManager.swift */; };
17 | 773E7C6526AD6B7100AC1A8A /* AlertPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6126AD6B7100AC1A8A /* AlertPresentationController.swift */; };
18 | 773E7C6726AD6B9B00AC1A8A /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6626AD6B9B00AC1A8A /* DetailViewController.swift */; };
19 | 773E7C6B26AD725800AC1A8A /* ActionSheetTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6A26AD725800AC1A8A /* ActionSheetTransitionManager.swift */; };
20 | 773E7C6D26AD72B900AC1A8A /* ActionSheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6C26AD72B900AC1A8A /* ActionSheetPresentationController.swift */; };
21 | 773E7C7026AD7D2400AC1A8A /* SlideTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C6F26AD7D2400AC1A8A /* SlideTransitionManager.swift */; };
22 | 773E7C7326AD7D5F00AC1A8A /* SlideTransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7226AD7D5F00AC1A8A /* SlideTransitionAnimator.swift */; };
23 | 773E7C7626AD82E900AC1A8A /* FancyTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7526AD82E900AC1A8A /* FancyTransitionManager.swift */; };
24 | 773E7C7826AD82F400AC1A8A /* FancyTransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7726AD82F400AC1A8A /* FancyTransitionAnimator.swift */; };
25 | 773E7C7A26AD94AD00AC1A8A /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7926AD94AD00AC1A8A /* UIColor+Extension.swift */; };
26 | 773E7C7C26ADAD2300AC1A8A /* FancyPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7B26ADAD2300AC1A8A /* FancyPresentationController.swift */; };
27 | 773E7C7E26ADB1A700AC1A8A /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773E7C7D26ADB1A700AC1A8A /* UIButton+Extension.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 773E7C4626AD6B1800AC1A8A /* CustomTransitions.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomTransitions.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 773E7C4926AD6B1800AC1A8A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
33 | 773E7C4B26AD6B1800AC1A8A /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
34 | 773E7C4D26AD6B1800AC1A8A /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = ""; };
35 | 773E7C5226AD6B1A00AC1A8A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
36 | 773E7C5526AD6B1A00AC1A8A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
37 | 773E7C5726AD6B1A00AC1A8A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
38 | 773E7C5F26AD6B7100AC1A8A /* AlertTransitionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertTransitionAnimator.swift; sourceTree = ""; };
39 | 773E7C6026AD6B7100AC1A8A /* AlertTransitionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertTransitionManager.swift; sourceTree = ""; };
40 | 773E7C6126AD6B7100AC1A8A /* AlertPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertPresentationController.swift; sourceTree = ""; };
41 | 773E7C6626AD6B9B00AC1A8A /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
42 | 773E7C6A26AD725800AC1A8A /* ActionSheetTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetTransitionManager.swift; sourceTree = ""; };
43 | 773E7C6C26AD72B900AC1A8A /* ActionSheetPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetPresentationController.swift; sourceTree = ""; };
44 | 773E7C6F26AD7D2400AC1A8A /* SlideTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideTransitionManager.swift; sourceTree = ""; };
45 | 773E7C7226AD7D5F00AC1A8A /* SlideTransitionAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SlideTransitionAnimator.swift; sourceTree = ""; };
46 | 773E7C7526AD82E900AC1A8A /* FancyTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTransitionManager.swift; sourceTree = ""; };
47 | 773E7C7726AD82F400AC1A8A /* FancyTransitionAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTransitionAnimator.swift; sourceTree = ""; };
48 | 773E7C7926AD94AD00AC1A8A /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; };
49 | 773E7C7B26ADAD2300AC1A8A /* FancyPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyPresentationController.swift; sourceTree = ""; };
50 | 773E7C7D26ADB1A700AC1A8A /* UIButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Extension.swift"; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 773E7C4326AD6B1800AC1A8A /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 773E7C3D26AD6B1800AC1A8A = {
65 | isa = PBXGroup;
66 | children = (
67 | 773E7C4826AD6B1800AC1A8A /* CustomTransitions */,
68 | 773E7C4726AD6B1800AC1A8A /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | 773E7C4726AD6B1800AC1A8A /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 773E7C4626AD6B1800AC1A8A /* CustomTransitions.app */,
76 | );
77 | name = Products;
78 | sourceTree = "";
79 | };
80 | 773E7C4826AD6B1800AC1A8A /* CustomTransitions */ = {
81 | isa = PBXGroup;
82 | children = (
83 | 773E7C4926AD6B1800AC1A8A /* AppDelegate.swift */,
84 | 773E7C4B26AD6B1800AC1A8A /* SceneDelegate.swift */,
85 | 773E7C4D26AD6B1800AC1A8A /* HomeViewController.swift */,
86 | 773E7C6626AD6B9B00AC1A8A /* DetailViewController.swift */,
87 | 773E7C6E26AD7CEE00AC1A8A /* Transitions */,
88 | 773E7C7926AD94AD00AC1A8A /* UIColor+Extension.swift */,
89 | 773E7C7D26ADB1A700AC1A8A /* UIButton+Extension.swift */,
90 | 773E7C5226AD6B1A00AC1A8A /* Assets.xcassets */,
91 | 773E7C5426AD6B1A00AC1A8A /* LaunchScreen.storyboard */,
92 | 773E7C5726AD6B1A00AC1A8A /* Info.plist */,
93 | );
94 | path = CustomTransitions;
95 | sourceTree = "";
96 | };
97 | 773E7C5D26AD6B7100AC1A8A /* Alert */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 773E7C6026AD6B7100AC1A8A /* AlertTransitionManager.swift */,
101 | 773E7C5F26AD6B7100AC1A8A /* AlertTransitionAnimator.swift */,
102 | 773E7C6126AD6B7100AC1A8A /* AlertPresentationController.swift */,
103 | );
104 | path = Alert;
105 | sourceTree = "";
106 | };
107 | 773E7C6926AD6BAE00AC1A8A /* ActionSheet */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 773E7C6A26AD725800AC1A8A /* ActionSheetTransitionManager.swift */,
111 | 773E7C6C26AD72B900AC1A8A /* ActionSheetPresentationController.swift */,
112 | );
113 | path = ActionSheet;
114 | sourceTree = "";
115 | };
116 | 773E7C6E26AD7CEE00AC1A8A /* Transitions */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 773E7C7126AD7D2B00AC1A8A /* Slide */,
120 | 773E7C6926AD6BAE00AC1A8A /* ActionSheet */,
121 | 773E7C5D26AD6B7100AC1A8A /* Alert */,
122 | 773E7C7426AD82B900AC1A8A /* Fancy */,
123 | );
124 | path = Transitions;
125 | sourceTree = "";
126 | };
127 | 773E7C7126AD7D2B00AC1A8A /* Slide */ = {
128 | isa = PBXGroup;
129 | children = (
130 | 773E7C6F26AD7D2400AC1A8A /* SlideTransitionManager.swift */,
131 | 773E7C7226AD7D5F00AC1A8A /* SlideTransitionAnimator.swift */,
132 | );
133 | path = Slide;
134 | sourceTree = "";
135 | };
136 | 773E7C7426AD82B900AC1A8A /* Fancy */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 773E7C7526AD82E900AC1A8A /* FancyTransitionManager.swift */,
140 | 773E7C7726AD82F400AC1A8A /* FancyTransitionAnimator.swift */,
141 | 773E7C7B26ADAD2300AC1A8A /* FancyPresentationController.swift */,
142 | );
143 | path = Fancy;
144 | sourceTree = "";
145 | };
146 | /* End PBXGroup section */
147 |
148 | /* Begin PBXNativeTarget section */
149 | 773E7C4526AD6B1800AC1A8A /* CustomTransitions */ = {
150 | isa = PBXNativeTarget;
151 | buildConfigurationList = 773E7C5A26AD6B1A00AC1A8A /* Build configuration list for PBXNativeTarget "CustomTransitions" */;
152 | buildPhases = (
153 | 773E7C4226AD6B1800AC1A8A /* Sources */,
154 | 773E7C4326AD6B1800AC1A8A /* Frameworks */,
155 | 773E7C4426AD6B1800AC1A8A /* Resources */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | );
161 | name = CustomTransitions;
162 | productName = CustomTransitions;
163 | productReference = 773E7C4626AD6B1800AC1A8A /* CustomTransitions.app */;
164 | productType = "com.apple.product-type.application";
165 | };
166 | /* End PBXNativeTarget section */
167 |
168 | /* Begin PBXProject section */
169 | 773E7C3E26AD6B1800AC1A8A /* Project object */ = {
170 | isa = PBXProject;
171 | attributes = {
172 | LastSwiftUpdateCheck = 1250;
173 | LastUpgradeCheck = 1250;
174 | TargetAttributes = {
175 | 773E7C4526AD6B1800AC1A8A = {
176 | CreatedOnToolsVersion = 12.5.1;
177 | };
178 | };
179 | };
180 | buildConfigurationList = 773E7C4126AD6B1800AC1A8A /* Build configuration list for PBXProject "CustomTransitions" */;
181 | compatibilityVersion = "Xcode 9.3";
182 | developmentRegion = en;
183 | hasScannedForEncodings = 0;
184 | knownRegions = (
185 | en,
186 | Base,
187 | );
188 | mainGroup = 773E7C3D26AD6B1800AC1A8A;
189 | productRefGroup = 773E7C4726AD6B1800AC1A8A /* Products */;
190 | projectDirPath = "";
191 | projectRoot = "";
192 | targets = (
193 | 773E7C4526AD6B1800AC1A8A /* CustomTransitions */,
194 | );
195 | };
196 | /* End PBXProject section */
197 |
198 | /* Begin PBXResourcesBuildPhase section */
199 | 773E7C4426AD6B1800AC1A8A /* Resources */ = {
200 | isa = PBXResourcesBuildPhase;
201 | buildActionMask = 2147483647;
202 | files = (
203 | 773E7C5626AD6B1A00AC1A8A /* LaunchScreen.storyboard in Resources */,
204 | 773E7C5326AD6B1A00AC1A8A /* Assets.xcassets in Resources */,
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | };
208 | /* End PBXResourcesBuildPhase section */
209 |
210 | /* Begin PBXSourcesBuildPhase section */
211 | 773E7C4226AD6B1800AC1A8A /* Sources */ = {
212 | isa = PBXSourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 773E7C7326AD7D5F00AC1A8A /* SlideTransitionAnimator.swift in Sources */,
216 | 773E7C7026AD7D2400AC1A8A /* SlideTransitionManager.swift in Sources */,
217 | 773E7C4E26AD6B1800AC1A8A /* HomeViewController.swift in Sources */,
218 | 773E7C7C26ADAD2300AC1A8A /* FancyPresentationController.swift in Sources */,
219 | 773E7C4A26AD6B1800AC1A8A /* AppDelegate.swift in Sources */,
220 | 773E7C7E26ADB1A700AC1A8A /* UIButton+Extension.swift in Sources */,
221 | 773E7C4C26AD6B1800AC1A8A /* SceneDelegate.swift in Sources */,
222 | 773E7C6426AD6B7100AC1A8A /* AlertTransitionManager.swift in Sources */,
223 | 773E7C6326AD6B7100AC1A8A /* AlertTransitionAnimator.swift in Sources */,
224 | 773E7C7A26AD94AD00AC1A8A /* UIColor+Extension.swift in Sources */,
225 | 773E7C6B26AD725800AC1A8A /* ActionSheetTransitionManager.swift in Sources */,
226 | 773E7C6526AD6B7100AC1A8A /* AlertPresentationController.swift in Sources */,
227 | 773E7C6726AD6B9B00AC1A8A /* DetailViewController.swift in Sources */,
228 | 773E7C7626AD82E900AC1A8A /* FancyTransitionManager.swift in Sources */,
229 | 773E7C6D26AD72B900AC1A8A /* ActionSheetPresentationController.swift in Sources */,
230 | 773E7C7826AD82F400AC1A8A /* FancyTransitionAnimator.swift in Sources */,
231 | );
232 | runOnlyForDeploymentPostprocessing = 0;
233 | };
234 | /* End PBXSourcesBuildPhase section */
235 |
236 | /* Begin PBXVariantGroup section */
237 | 773E7C5426AD6B1A00AC1A8A /* LaunchScreen.storyboard */ = {
238 | isa = PBXVariantGroup;
239 | children = (
240 | 773E7C5526AD6B1A00AC1A8A /* Base */,
241 | );
242 | name = LaunchScreen.storyboard;
243 | sourceTree = "";
244 | };
245 | /* End PBXVariantGroup section */
246 |
247 | /* Begin XCBuildConfiguration section */
248 | 773E7C5826AD6B1A00AC1A8A /* Debug */ = {
249 | isa = XCBuildConfiguration;
250 | buildSettings = {
251 | ALWAYS_SEARCH_USER_PATHS = NO;
252 | CLANG_ANALYZER_NONNULL = YES;
253 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
254 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
255 | CLANG_CXX_LIBRARY = "libc++";
256 | CLANG_ENABLE_MODULES = YES;
257 | CLANG_ENABLE_OBJC_ARC = YES;
258 | CLANG_ENABLE_OBJC_WEAK = YES;
259 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
260 | CLANG_WARN_BOOL_CONVERSION = YES;
261 | CLANG_WARN_COMMA = YES;
262 | CLANG_WARN_CONSTANT_CONVERSION = YES;
263 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
264 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
265 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
266 | CLANG_WARN_EMPTY_BODY = YES;
267 | CLANG_WARN_ENUM_CONVERSION = YES;
268 | CLANG_WARN_INFINITE_RECURSION = YES;
269 | CLANG_WARN_INT_CONVERSION = YES;
270 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
271 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
272 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
274 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
275 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
276 | CLANG_WARN_STRICT_PROTOTYPES = YES;
277 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
278 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
279 | CLANG_WARN_UNREACHABLE_CODE = YES;
280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
281 | COPY_PHASE_STRIP = NO;
282 | DEBUG_INFORMATION_FORMAT = dwarf;
283 | ENABLE_STRICT_OBJC_MSGSEND = YES;
284 | ENABLE_TESTABILITY = YES;
285 | GCC_C_LANGUAGE_STANDARD = gnu11;
286 | GCC_DYNAMIC_NO_PIC = NO;
287 | GCC_NO_COMMON_BLOCKS = YES;
288 | GCC_OPTIMIZATION_LEVEL = 0;
289 | GCC_PREPROCESSOR_DEFINITIONS = (
290 | "DEBUG=1",
291 | "$(inherited)",
292 | );
293 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
294 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
295 | GCC_WARN_UNDECLARED_SELECTOR = YES;
296 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
297 | GCC_WARN_UNUSED_FUNCTION = YES;
298 | GCC_WARN_UNUSED_VARIABLE = YES;
299 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
300 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
301 | MTL_FAST_MATH = YES;
302 | ONLY_ACTIVE_ARCH = YES;
303 | SDKROOT = iphoneos;
304 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
305 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
306 | };
307 | name = Debug;
308 | };
309 | 773E7C5926AD6B1A00AC1A8A /* Release */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | ALWAYS_SEARCH_USER_PATHS = NO;
313 | CLANG_ANALYZER_NONNULL = YES;
314 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
316 | CLANG_CXX_LIBRARY = "libc++";
317 | CLANG_ENABLE_MODULES = YES;
318 | CLANG_ENABLE_OBJC_ARC = YES;
319 | CLANG_ENABLE_OBJC_WEAK = YES;
320 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
321 | CLANG_WARN_BOOL_CONVERSION = YES;
322 | CLANG_WARN_COMMA = YES;
323 | CLANG_WARN_CONSTANT_CONVERSION = YES;
324 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
325 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
326 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
327 | CLANG_WARN_EMPTY_BODY = YES;
328 | CLANG_WARN_ENUM_CONVERSION = YES;
329 | CLANG_WARN_INFINITE_RECURSION = YES;
330 | CLANG_WARN_INT_CONVERSION = YES;
331 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
333 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
334 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
335 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
337 | CLANG_WARN_STRICT_PROTOTYPES = YES;
338 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
339 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
340 | CLANG_WARN_UNREACHABLE_CODE = YES;
341 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
342 | COPY_PHASE_STRIP = NO;
343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
344 | ENABLE_NS_ASSERTIONS = NO;
345 | ENABLE_STRICT_OBJC_MSGSEND = YES;
346 | GCC_C_LANGUAGE_STANDARD = gnu11;
347 | GCC_NO_COMMON_BLOCKS = YES;
348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
350 | GCC_WARN_UNDECLARED_SELECTOR = YES;
351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
352 | GCC_WARN_UNUSED_FUNCTION = YES;
353 | GCC_WARN_UNUSED_VARIABLE = YES;
354 | IPHONEOS_DEPLOYMENT_TARGET = 14.5;
355 | MTL_ENABLE_DEBUG_INFO = NO;
356 | MTL_FAST_MATH = YES;
357 | SDKROOT = iphoneos;
358 | SWIFT_COMPILATION_MODE = wholemodule;
359 | SWIFT_OPTIMIZATION_LEVEL = "-O";
360 | VALIDATE_PRODUCT = YES;
361 | };
362 | name = Release;
363 | };
364 | 773E7C5B26AD6B1A00AC1A8A /* Debug */ = {
365 | isa = XCBuildConfiguration;
366 | buildSettings = {
367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
368 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
369 | CODE_SIGN_STYLE = Automatic;
370 | DEVELOPMENT_TEAM = 3XSV7BVV48;
371 | INFOPLIST_FILE = CustomTransitions/Info.plist;
372 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
373 | LD_RUNPATH_SEARCH_PATHS = (
374 | "$(inherited)",
375 | "@executable_path/Frameworks",
376 | );
377 | PRODUCT_BUNDLE_IDENTIFIER = com.ondrejkorol.CustomTransitions;
378 | PRODUCT_NAME = "$(TARGET_NAME)";
379 | SWIFT_VERSION = 5.0;
380 | TARGETED_DEVICE_FAMILY = "1,2";
381 | };
382 | name = Debug;
383 | };
384 | 773E7C5C26AD6B1A00AC1A8A /* Release */ = {
385 | isa = XCBuildConfiguration;
386 | buildSettings = {
387 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
388 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
389 | CODE_SIGN_STYLE = Automatic;
390 | DEVELOPMENT_TEAM = 3XSV7BVV48;
391 | INFOPLIST_FILE = CustomTransitions/Info.plist;
392 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
393 | LD_RUNPATH_SEARCH_PATHS = (
394 | "$(inherited)",
395 | "@executable_path/Frameworks",
396 | );
397 | PRODUCT_BUNDLE_IDENTIFIER = com.ondrejkorol.CustomTransitions;
398 | PRODUCT_NAME = "$(TARGET_NAME)";
399 | SWIFT_VERSION = 5.0;
400 | TARGETED_DEVICE_FAMILY = "1,2";
401 | };
402 | name = Release;
403 | };
404 | /* End XCBuildConfiguration section */
405 |
406 | /* Begin XCConfigurationList section */
407 | 773E7C4126AD6B1800AC1A8A /* Build configuration list for PBXProject "CustomTransitions" */ = {
408 | isa = XCConfigurationList;
409 | buildConfigurations = (
410 | 773E7C5826AD6B1A00AC1A8A /* Debug */,
411 | 773E7C5926AD6B1A00AC1A8A /* Release */,
412 | );
413 | defaultConfigurationIsVisible = 0;
414 | defaultConfigurationName = Release;
415 | };
416 | 773E7C5A26AD6B1A00AC1A8A /* Build configuration list for PBXNativeTarget "CustomTransitions" */ = {
417 | isa = XCConfigurationList;
418 | buildConfigurations = (
419 | 773E7C5B26AD6B1A00AC1A8A /* Debug */,
420 | 773E7C5C26AD6B1A00AC1A8A /* Release */,
421 | );
422 | defaultConfigurationIsVisible = 0;
423 | defaultConfigurationName = Release;
424 | };
425 | /* End XCConfigurationList section */
426 | };
427 | rootObject = 773E7C3E26AD6B1800AC1A8A /* Project object */;
428 | }
429 |
--------------------------------------------------------------------------------