├── draggableViewController.gif
├── DraggableViewController.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── README.md
├── DraggableViewController
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── BottomBar.swift
├── Info.plist
├── NextViewController.swift
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── BaseAnimator.swift
├── MiniToLargeViewInteractive.swift
├── MiniToLargeViewAnimator.swift
└── ViewController.swift
└── .gitignore
/draggableViewController.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/canopas/DraggableViewController/HEAD/draggableViewController.gif
--------------------------------------------------------------------------------
/DraggableViewController.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DraggableViewController
2 |
3 | Swift version of Objective-C DraggableViewController in tutorial http://imnotyourson.com/draggable-view-controller-interactive-view-controller/
4 |
5 | [](https://swift.org/) [](https://developer.apple.com/xcode/)
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/DraggableViewController/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | private func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/DraggableViewController/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/DraggableViewController/BottomBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DummyView.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class BottomBar: UIView {
12 |
13 | //MARK: - Properties
14 | static let bottomBarHeight: CGFloat = 50
15 | var button: UIButton!
16 |
17 | //MARK: - Lifecycle
18 | override init(frame: CGRect) {
19 | super.init(frame: frame)
20 | setupSubview()
21 | }
22 |
23 | required init?(coder aDecoder: NSCoder) {
24 | fatalError("init(coder:) has not been implemented")
25 | }
26 |
27 | func setupSubview() {
28 | self.backgroundColor = UIColor.gray
29 |
30 | button = UIButton()
31 | button.setTitle("Tap or drag me", for: .normal)
32 | button.backgroundColor = UIColor.gray
33 | button.translatesAutoresizingMaskIntoConstraints = false
34 | self.addSubview(button)
35 |
36 | button.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
37 | button.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/DraggableViewController/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 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/DraggableViewController/NextViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NextViewController.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class NextViewController: UIViewController {
12 |
13 | //MARK: - Properties
14 | var rootViewController: ViewController?
15 |
16 | //MARK: - Lifecycle
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | self.view.backgroundColor = UIColor.brown
20 |
21 | let button = UIButton()
22 | button.setTitle("Dismiss", for: .normal)
23 | button.addTarget(self, action: #selector(self.buttonTapped), for: .touchUpInside)
24 | button.translatesAutoresizingMaskIntoConstraints = false
25 | self.view.addSubview(button)
26 |
27 | button.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 6).isActive = true
28 | if #available(iOS 11.0, *) {
29 | button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
30 | } else {
31 | button.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
32 | }
33 |
34 | }
35 |
36 | //MARK: - Actions
37 | @objc func buttonTapped() {
38 | rootViewController?.disableInteractivePlayerTransitioning = true
39 | self.dismiss(animated: true) { [unowned self] in
40 | self.rootViewController?.disableInteractivePlayerTransitioning = false
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | # Xcode
4 | #
5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
6 |
7 | ## Build generated
8 | build/
9 | DerivedData
10 |
11 | ## Various settings
12 | *.pbxuser
13 | !default.pbxuser
14 | *.mode1v3
15 | !default.mode1v3
16 | *.mode2v3
17 | !default.mode2v3
18 | *.perspectivev3
19 | !default.perspectivev3
20 | xcuserdata
21 |
22 | ## Other
23 | *.xccheckout
24 | *.moved-aside
25 | *.xcuserstate
26 | *.xcscmblueprint
27 |
28 | ## Obj-C/Swift specific
29 | *.hmap
30 | *.ipa
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
63 |
64 | fastlane/report.xml
65 | fastlane/screenshots
66 |
--------------------------------------------------------------------------------
/DraggableViewController/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 |
--------------------------------------------------------------------------------
/DraggableViewController/Base.lproj/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 |
31 |
--------------------------------------------------------------------------------
/DraggableViewController/BaseAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseAnimator.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum ModalAnimatedTransitioningType {
12 | case Present
13 | case Dismiss
14 | }
15 |
16 | class BaseAnimator: NSObject {
17 |
18 | var transitionType: ModalAnimatedTransitioningType = .Present
19 |
20 | func animatePresentingInContext(transitionContext: UIViewControllerContextTransitioning, fromVC: UIViewController, toVC: UIViewController) {
21 | NSException(name:NSExceptionName.internalInconsistencyException, reason:"\(#function) must be overridden in a subclass/category", userInfo:nil).raise()
22 | }
23 |
24 | func animateDismissingInContext(transitionContext: UIViewControllerContextTransitioning, fromVC: UIViewController, toVC: UIViewController) {
25 | NSException(name:NSExceptionName.internalInconsistencyException, reason:"\(#function) must be overridden in a subclass/category", userInfo:nil).raise()
26 | }
27 | }
28 |
29 | //MARK: - UIViewControllerAnimatedTransitioning
30 | extension BaseAnimator: UIViewControllerAnimatedTransitioning {
31 |
32 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
33 | let from = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
34 | let to = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
35 |
36 | if let from = from, let to = to {
37 | switch transitionType {
38 | case .Present:
39 | animatePresentingInContext(transitionContext: transitionContext, fromVC: from, toVC: to)
40 | case .Dismiss:
41 | animateDismissingInContext(transitionContext: transitionContext, fromVC: from, toVC: to)
42 | }
43 | }
44 | }
45 |
46 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
47 | NSException(name:NSExceptionName.internalInconsistencyException, reason:"\(#function) must be overridden in a subclass/category", userInfo:nil).raise()
48 | return 0
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/DraggableViewController/MiniToLargeViewInteractive.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiniToLargeViewInteractive.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MiniToLargeViewInteractive: UIPercentDrivenInteractiveTransition {
12 |
13 | //MARK: - Properties
14 | var viewController: UIViewController?
15 | var presentViewController: UIViewController?
16 | var pan: UIPanGestureRecognizer!
17 |
18 | var shouldComplete = false
19 | var lastProgress: CGFloat?
20 |
21 | //MARK: - Lifecycle
22 | func attachToViewController(viewController: UIViewController, withView view: UIView, presentViewController: UIViewController?) {
23 | self.viewController = viewController
24 | self.presentViewController = presentViewController
25 | pan = UIPanGestureRecognizer(target: self, action: #selector(self.onPan(pan:)))
26 | view.addGestureRecognizer(pan)
27 | }
28 |
29 | //MARK: - Actions
30 | @objc func onPan(pan: UIPanGestureRecognizer) {
31 | let translation = pan.translation(in: pan.view?.superview)
32 |
33 | //Represents the percentage of the transition that must be completed before allowing to complete.
34 | let percentThreshold: CGFloat = 0.2
35 | //Represents the difference between progress that is required to trigger the completion of the transition.
36 | let automaticOverrideThreshold: CGFloat = 0.03
37 |
38 | let screenHeight: CGFloat = UIScreen.main.bounds.size.height - BottomBar.bottomBarHeight
39 | let dragAmount: CGFloat = (presentViewController == nil) ? screenHeight : -screenHeight
40 | var progress: CGFloat = translation.y / dragAmount
41 |
42 | progress = fmax(progress, 0)
43 | progress = fmin(progress, 1)
44 |
45 | switch pan.state {
46 | case .began:
47 | if let presentViewController = presentViewController {
48 | viewController?.present(presentViewController, animated: true, completion: nil)
49 | } else {
50 | viewController?.dismiss(animated: true, completion: nil)
51 | }
52 |
53 | case .changed:
54 | guard let lastProgress = lastProgress else {return}
55 |
56 | // When swiping back
57 | if lastProgress > progress {
58 | shouldComplete = false
59 | // When swiping quick to the right
60 | } else if progress > lastProgress + automaticOverrideThreshold {
61 | shouldComplete = true
62 | } else {
63 | // Normal behavior
64 | shouldComplete = progress > percentThreshold
65 | }
66 | update(progress)
67 |
68 | case .ended, .cancelled:
69 | if pan.state == .cancelled || shouldComplete == false {
70 | cancel()
71 | } else {
72 | finish()
73 | }
74 |
75 | default:
76 | break
77 | }
78 |
79 | lastProgress = progress
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/DraggableViewController/MiniToLargeViewAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiniToLargeViewAnimator.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MiniToLargeViewAnimator: BaseAnimator {
12 |
13 | //MARK: - Properties
14 | var initialY: CGFloat = 0
15 |
16 |
17 | //MARK: - Lifecycle
18 | override func animatePresentingInContext(transitionContext: UIViewControllerContextTransitioning, fromVC: UIViewController, toVC: UIViewController) {
19 |
20 | let fromRect = transitionContext.initialFrame(for: fromVC)
21 | var toRect = fromRect
22 | toRect.origin.y = toRect.size.height - initialY
23 |
24 | toVC.view.frame = toRect
25 | let container = transitionContext.containerView
26 | let imageView = fakeMiniView()
27 |
28 | toVC.view.addSubview(imageView)
29 | container.addSubview(fromVC.view)
30 | container.addSubview(toVC.view)
31 |
32 | let animOptions: UIView.AnimationOptions = transitionContext.isInteractive ? [UIView.AnimationOptions.curveLinear] : []
33 |
34 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: animOptions, animations: {
35 | toVC.view.frame = fromRect
36 | imageView.alpha = 0
37 | }) { (finished) in
38 | imageView.removeFromSuperview()
39 | if transitionContext.transitionWasCancelled {
40 | transitionContext.completeTransition(false)
41 | } else {
42 | transitionContext.completeTransition(true)
43 | }
44 | }
45 | }
46 |
47 | override func animateDismissingInContext(transitionContext: UIViewControllerContextTransitioning,
48 | fromVC: UIViewController,
49 | toVC: UIViewController) {
50 |
51 | var fromRect = transitionContext.initialFrame(for: fromVC)
52 | fromRect.origin.y = fromRect.size.height - initialY
53 |
54 | let imageView = fakeMiniView()
55 | imageView.alpha = 0
56 | fromVC.view.addSubview(imageView)
57 |
58 | let container = transitionContext.containerView
59 | container.addSubview(toVC.view)
60 | container.addSubview(fromVC.view)
61 |
62 | let animOptions: UIView.AnimationOptions = transitionContext.isInteractive ? [UIView.AnimationOptions.curveLinear] : []
63 |
64 | UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: animOptions, animations: {
65 | fromVC.view.frame = fromRect
66 | imageView.alpha = 1
67 | }) { (finished) in
68 | imageView.removeFromSuperview()
69 | if transitionContext.transitionWasCancelled {
70 | transitionContext.completeTransition(false)
71 | } else {
72 | transitionContext.completeTransition(true)
73 | }
74 | }
75 | }
76 |
77 | override func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
78 | return transitionContext!.isInteractive ? 0.4 : 0.3
79 | }
80 |
81 | //MARK: - Helper
82 | func fakeMiniView() -> UIView {
83 | // Fake a mini view, two ways:
84 | // 1. create a new certain one
85 | // 2. snapshot old one.
86 |
87 | return BottomBar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: BottomBar.bottomBarHeight))
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/DraggableViewController/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // DraggableViewController
4 | //
5 | // Created by Jiri Ostatnicky on 18/05/16.
6 | // Copyright © 2016 Jiri Ostatnicky. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | //MARK: - Properties
14 | var disableInteractivePlayerTransitioning = false
15 |
16 | var bottomBar: BottomBar!
17 | var nextViewController: NextViewController!
18 | var presentInteractor: MiniToLargeViewInteractive!
19 | var dismissInteractor: MiniToLargeViewInteractive!
20 |
21 | //MARK: - Lifecycle
22 | override func viewDidLoad() {
23 | super.viewDidLoad()
24 |
25 | prepareView()
26 | }
27 |
28 | func prepareView() {
29 | bottomBar = BottomBar()
30 | bottomBar.button.addTarget(self, action: #selector(self.bottomButtonTapped), for: .touchUpInside)
31 | bottomBar.translatesAutoresizingMaskIntoConstraints = false
32 | self.view.addSubview(bottomBar)
33 |
34 | [bottomBar.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0),
35 | bottomBar.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0),
36 | bottomBar.heightAnchor.constraint(equalToConstant: 50)].forEach({ $0.isActive = true })
37 | if #available(iOS 11.0, *) {
38 | bottomBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
39 | } else {
40 | bottomBar.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
41 | }
42 |
43 | nextViewController = NextViewController()
44 | nextViewController.rootViewController = self
45 | nextViewController.transitioningDelegate = self
46 | nextViewController.modalPresentationStyle = .fullScreen
47 |
48 | presentInteractor = MiniToLargeViewInteractive()
49 | presentInteractor.attachToViewController(viewController: self, withView: bottomBar, presentViewController: nextViewController)
50 | dismissInteractor = MiniToLargeViewInteractive()
51 | dismissInteractor.attachToViewController(viewController: nextViewController, withView: nextViewController.view, presentViewController: nil)
52 | }
53 |
54 | //MARK: - Actions
55 | @objc func bottomButtonTapped() {
56 | disableInteractivePlayerTransitioning = true
57 | self.present(nextViewController, animated: true) { [unowned self] in
58 | self.disableInteractivePlayerTransitioning = false
59 | }
60 | }
61 | }
62 |
63 | //MARK: - UIViewControllerTransitioningDelegate
64 | extension ViewController: UIViewControllerTransitioningDelegate {
65 |
66 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
67 | let animator = MiniToLargeViewAnimator()
68 | if #available(iOS 11.0, *) {
69 | animator.initialY = BottomBar.bottomBarHeight + self.view.safeAreaInsets.bottom
70 | } else {
71 | animator.initialY = BottomBar.bottomBarHeight
72 | }
73 | animator.transitionType = .Present
74 | return animator
75 | }
76 |
77 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
78 | let animator = MiniToLargeViewAnimator()
79 | if #available(iOS 11.0, *) {
80 | animator.initialY = BottomBar.bottomBarHeight + self.view.safeAreaInsets.bottom
81 | } else {
82 | animator.initialY = BottomBar.bottomBarHeight
83 | }
84 | animator.transitionType = .Dismiss
85 | return animator
86 | }
87 |
88 | func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
89 | guard !disableInteractivePlayerTransitioning else { return nil }
90 | return presentInteractor
91 | }
92 |
93 | func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
94 | guard !disableInteractivePlayerTransitioning else { return nil }
95 | return dismissInteractor
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/DraggableViewController.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 459801662168993F004999D6 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 459801652168993F004999D6 /* README.md */; };
11 | 4B5F2C881CECAF590001CEFE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2C871CECAF590001CEFE /* AppDelegate.swift */; };
12 | 4B5F2C8A1CECAF590001CEFE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2C891CECAF590001CEFE /* ViewController.swift */; };
13 | 4B5F2C8D1CECAF5A0001CEFE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B5F2C8B1CECAF5A0001CEFE /* Main.storyboard */; };
14 | 4B5F2C8F1CECAF5A0001CEFE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4B5F2C8E1CECAF5A0001CEFE /* Assets.xcassets */; };
15 | 4B5F2C921CECAF5A0001CEFE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B5F2C901CECAF5A0001CEFE /* LaunchScreen.storyboard */; };
16 | 4B5F2C9A1CECB0B40001CEFE /* NextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2C991CECB0B40001CEFE /* NextViewController.swift */; };
17 | 4B5F2C9C1CECB0EF0001CEFE /* BaseAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2C9B1CECB0EF0001CEFE /* BaseAnimator.swift */; };
18 | 4B5F2C9F1CECB65F0001CEFE /* MiniToLargeViewAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2C9E1CECB65F0001CEFE /* MiniToLargeViewAnimator.swift */; };
19 | 4B5F2CA11CECB8350001CEFE /* MiniToLargeViewInteractive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2CA01CECB8350001CEFE /* MiniToLargeViewInteractive.swift */; };
20 | 4B5F2CA31CECBB9A0001CEFE /* BottomBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5F2CA21CECBB9A0001CEFE /* BottomBar.swift */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXFileReference section */
24 | 459801652168993F004999D6 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
25 | 4B5F2C841CECAF590001CEFE /* DraggableViewController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DraggableViewController.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | 4B5F2C871CECAF590001CEFE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
27 | 4B5F2C891CECAF590001CEFE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
28 | 4B5F2C8C1CECAF5A0001CEFE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
29 | 4B5F2C8E1CECAF5A0001CEFE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | 4B5F2C911CECAF5A0001CEFE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
31 | 4B5F2C931CECAF5A0001CEFE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 4B5F2C991CECB0B40001CEFE /* NextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NextViewController.swift; sourceTree = ""; };
33 | 4B5F2C9B1CECB0EF0001CEFE /* BaseAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseAnimator.swift; sourceTree = ""; };
34 | 4B5F2C9E1CECB65F0001CEFE /* MiniToLargeViewAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MiniToLargeViewAnimator.swift; sourceTree = ""; };
35 | 4B5F2CA01CECB8350001CEFE /* MiniToLargeViewInteractive.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MiniToLargeViewInteractive.swift; sourceTree = ""; };
36 | 4B5F2CA21CECBB9A0001CEFE /* BottomBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomBar.swift; sourceTree = ""; };
37 | /* End PBXFileReference section */
38 |
39 | /* Begin PBXFrameworksBuildPhase section */
40 | 4B5F2C811CECAF590001CEFE /* Frameworks */ = {
41 | isa = PBXFrameworksBuildPhase;
42 | buildActionMask = 2147483647;
43 | files = (
44 | );
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXFrameworksBuildPhase section */
48 |
49 | /* Begin PBXGroup section */
50 | 4B5F2C7B1CECAF590001CEFE = {
51 | isa = PBXGroup;
52 | children = (
53 | 459801652168993F004999D6 /* README.md */,
54 | 4B5F2C861CECAF590001CEFE /* DraggableViewController */,
55 | 4B5F2C851CECAF590001CEFE /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | 4B5F2C851CECAF590001CEFE /* Products */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 4B5F2C841CECAF590001CEFE /* DraggableViewController.app */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | 4B5F2C861CECAF590001CEFE /* DraggableViewController */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 4B5F2C871CECAF590001CEFE /* AppDelegate.swift */,
71 | 4B5F2C891CECAF590001CEFE /* ViewController.swift */,
72 | 4B5F2C991CECB0B40001CEFE /* NextViewController.swift */,
73 | 4B5F2CA21CECBB9A0001CEFE /* BottomBar.swift */,
74 | 4B5F2C9D1CECB3E00001CEFE /* Transition Animators */,
75 | 4B5F2C8B1CECAF5A0001CEFE /* Main.storyboard */,
76 | 4B5F2C8E1CECAF5A0001CEFE /* Assets.xcassets */,
77 | 4B5F2C901CECAF5A0001CEFE /* LaunchScreen.storyboard */,
78 | 4B5F2C931CECAF5A0001CEFE /* Info.plist */,
79 | );
80 | path = DraggableViewController;
81 | sourceTree = "";
82 | };
83 | 4B5F2C9D1CECB3E00001CEFE /* Transition Animators */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 4B5F2C9B1CECB0EF0001CEFE /* BaseAnimator.swift */,
87 | 4B5F2C9E1CECB65F0001CEFE /* MiniToLargeViewAnimator.swift */,
88 | 4B5F2CA01CECB8350001CEFE /* MiniToLargeViewInteractive.swift */,
89 | );
90 | name = "Transition Animators";
91 | sourceTree = "";
92 | };
93 | /* End PBXGroup section */
94 |
95 | /* Begin PBXNativeTarget section */
96 | 4B5F2C831CECAF590001CEFE /* DraggableViewController */ = {
97 | isa = PBXNativeTarget;
98 | buildConfigurationList = 4B5F2C961CECAF5A0001CEFE /* Build configuration list for PBXNativeTarget "DraggableViewController" */;
99 | buildPhases = (
100 | 4B5F2C801CECAF590001CEFE /* Sources */,
101 | 4B5F2C811CECAF590001CEFE /* Frameworks */,
102 | 4B5F2C821CECAF590001CEFE /* Resources */,
103 | );
104 | buildRules = (
105 | );
106 | dependencies = (
107 | );
108 | name = DraggableViewController;
109 | productName = DraggableViewController;
110 | productReference = 4B5F2C841CECAF590001CEFE /* DraggableViewController.app */;
111 | productType = "com.apple.product-type.application";
112 | };
113 | /* End PBXNativeTarget section */
114 |
115 | /* Begin PBXProject section */
116 | 4B5F2C7C1CECAF590001CEFE /* Project object */ = {
117 | isa = PBXProject;
118 | attributes = {
119 | LastSwiftUpdateCheck = 0730;
120 | LastUpgradeCheck = 1000;
121 | ORGANIZATIONNAME = "Jiri Ostatnicky";
122 | TargetAttributes = {
123 | 4B5F2C831CECAF590001CEFE = {
124 | CreatedOnToolsVersion = 7.3.1;
125 | LastSwiftMigration = 1000;
126 | };
127 | };
128 | };
129 | buildConfigurationList = 4B5F2C7F1CECAF590001CEFE /* Build configuration list for PBXProject "DraggableViewController" */;
130 | compatibilityVersion = "Xcode 3.2";
131 | developmentRegion = English;
132 | hasScannedForEncodings = 0;
133 | knownRegions = (
134 | en,
135 | Base,
136 | );
137 | mainGroup = 4B5F2C7B1CECAF590001CEFE;
138 | productRefGroup = 4B5F2C851CECAF590001CEFE /* Products */;
139 | projectDirPath = "";
140 | projectRoot = "";
141 | targets = (
142 | 4B5F2C831CECAF590001CEFE /* DraggableViewController */,
143 | );
144 | };
145 | /* End PBXProject section */
146 |
147 | /* Begin PBXResourcesBuildPhase section */
148 | 4B5F2C821CECAF590001CEFE /* Resources */ = {
149 | isa = PBXResourcesBuildPhase;
150 | buildActionMask = 2147483647;
151 | files = (
152 | 4B5F2C921CECAF5A0001CEFE /* LaunchScreen.storyboard in Resources */,
153 | 4B5F2C8F1CECAF5A0001CEFE /* Assets.xcassets in Resources */,
154 | 459801662168993F004999D6 /* README.md in Resources */,
155 | 4B5F2C8D1CECAF5A0001CEFE /* Main.storyboard in Resources */,
156 | );
157 | runOnlyForDeploymentPostprocessing = 0;
158 | };
159 | /* End PBXResourcesBuildPhase section */
160 |
161 | /* Begin PBXSourcesBuildPhase section */
162 | 4B5F2C801CECAF590001CEFE /* Sources */ = {
163 | isa = PBXSourcesBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | 4B5F2CA11CECB8350001CEFE /* MiniToLargeViewInteractive.swift in Sources */,
167 | 4B5F2C8A1CECAF590001CEFE /* ViewController.swift in Sources */,
168 | 4B5F2CA31CECBB9A0001CEFE /* BottomBar.swift in Sources */,
169 | 4B5F2C9A1CECB0B40001CEFE /* NextViewController.swift in Sources */,
170 | 4B5F2C9F1CECB65F0001CEFE /* MiniToLargeViewAnimator.swift in Sources */,
171 | 4B5F2C881CECAF590001CEFE /* AppDelegate.swift in Sources */,
172 | 4B5F2C9C1CECB0EF0001CEFE /* BaseAnimator.swift in Sources */,
173 | );
174 | runOnlyForDeploymentPostprocessing = 0;
175 | };
176 | /* End PBXSourcesBuildPhase section */
177 |
178 | /* Begin PBXVariantGroup section */
179 | 4B5F2C8B1CECAF5A0001CEFE /* Main.storyboard */ = {
180 | isa = PBXVariantGroup;
181 | children = (
182 | 4B5F2C8C1CECAF5A0001CEFE /* Base */,
183 | );
184 | name = Main.storyboard;
185 | sourceTree = "";
186 | };
187 | 4B5F2C901CECAF5A0001CEFE /* LaunchScreen.storyboard */ = {
188 | isa = PBXVariantGroup;
189 | children = (
190 | 4B5F2C911CECAF5A0001CEFE /* Base */,
191 | );
192 | name = LaunchScreen.storyboard;
193 | sourceTree = "";
194 | };
195 | /* End PBXVariantGroup section */
196 |
197 | /* Begin XCBuildConfiguration section */
198 | 4B5F2C941CECAF5A0001CEFE /* Debug */ = {
199 | isa = XCBuildConfiguration;
200 | buildSettings = {
201 | ALWAYS_SEARCH_USER_PATHS = NO;
202 | CLANG_ANALYZER_NONNULL = YES;
203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
204 | CLANG_CXX_LIBRARY = "libc++";
205 | CLANG_ENABLE_MODULES = YES;
206 | CLANG_ENABLE_OBJC_ARC = YES;
207 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
208 | CLANG_WARN_BOOL_CONVERSION = YES;
209 | CLANG_WARN_COMMA = YES;
210 | CLANG_WARN_CONSTANT_CONVERSION = YES;
211 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
212 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
213 | CLANG_WARN_EMPTY_BODY = YES;
214 | CLANG_WARN_ENUM_CONVERSION = YES;
215 | CLANG_WARN_INFINITE_RECURSION = YES;
216 | CLANG_WARN_INT_CONVERSION = YES;
217 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
218 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
219 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
220 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
222 | CLANG_WARN_STRICT_PROTOTYPES = YES;
223 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
224 | CLANG_WARN_UNREACHABLE_CODE = YES;
225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
226 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
227 | COPY_PHASE_STRIP = NO;
228 | DEBUG_INFORMATION_FORMAT = dwarf;
229 | ENABLE_STRICT_OBJC_MSGSEND = YES;
230 | ENABLE_TESTABILITY = YES;
231 | GCC_C_LANGUAGE_STANDARD = gnu99;
232 | GCC_DYNAMIC_NO_PIC = NO;
233 | GCC_NO_COMMON_BLOCKS = YES;
234 | GCC_OPTIMIZATION_LEVEL = 0;
235 | GCC_PREPROCESSOR_DEFINITIONS = (
236 | "DEBUG=1",
237 | "$(inherited)",
238 | );
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
246 | MTL_ENABLE_DEBUG_INFO = YES;
247 | ONLY_ACTIVE_ARCH = YES;
248 | SDKROOT = iphoneos;
249 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
250 | SWIFT_VERSION = 4.0;
251 | };
252 | name = Debug;
253 | };
254 | 4B5F2C951CECAF5A0001CEFE /* Release */ = {
255 | isa = XCBuildConfiguration;
256 | buildSettings = {
257 | ALWAYS_SEARCH_USER_PATHS = NO;
258 | CLANG_ANALYZER_NONNULL = YES;
259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
260 | CLANG_CXX_LIBRARY = "libc++";
261 | CLANG_ENABLE_MODULES = YES;
262 | CLANG_ENABLE_OBJC_ARC = YES;
263 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
264 | CLANG_WARN_BOOL_CONVERSION = YES;
265 | CLANG_WARN_COMMA = YES;
266 | CLANG_WARN_CONSTANT_CONVERSION = YES;
267 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
268 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
269 | CLANG_WARN_EMPTY_BODY = YES;
270 | CLANG_WARN_ENUM_CONVERSION = YES;
271 | CLANG_WARN_INFINITE_RECURSION = YES;
272 | CLANG_WARN_INT_CONVERSION = YES;
273 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
274 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
275 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
276 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
277 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
278 | CLANG_WARN_STRICT_PROTOTYPES = YES;
279 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
280 | CLANG_WARN_UNREACHABLE_CODE = YES;
281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
282 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
283 | COPY_PHASE_STRIP = NO;
284 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
285 | ENABLE_NS_ASSERTIONS = NO;
286 | ENABLE_STRICT_OBJC_MSGSEND = YES;
287 | GCC_C_LANGUAGE_STANDARD = gnu99;
288 | GCC_NO_COMMON_BLOCKS = YES;
289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
291 | GCC_WARN_UNDECLARED_SELECTOR = YES;
292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
293 | GCC_WARN_UNUSED_FUNCTION = YES;
294 | GCC_WARN_UNUSED_VARIABLE = YES;
295 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
296 | MTL_ENABLE_DEBUG_INFO = NO;
297 | SDKROOT = iphoneos;
298 | SWIFT_COMPILATION_MODE = wholemodule;
299 | SWIFT_VERSION = 4.0;
300 | VALIDATE_PRODUCT = YES;
301 | };
302 | name = Release;
303 | };
304 | 4B5F2C971CECAF5A0001CEFE /* Debug */ = {
305 | isa = XCBuildConfiguration;
306 | buildSettings = {
307 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
308 | INFOPLIST_FILE = DraggableViewController/Info.plist;
309 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
310 | PRODUCT_BUNDLE_IDENTIFIER = com.ostatnicky.DraggableViewController;
311 | PRODUCT_NAME = "$(TARGET_NAME)";
312 | SWIFT_VERSION = 4.2;
313 | };
314 | name = Debug;
315 | };
316 | 4B5F2C981CECAF5A0001CEFE /* Release */ = {
317 | isa = XCBuildConfiguration;
318 | buildSettings = {
319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
320 | INFOPLIST_FILE = DraggableViewController/Info.plist;
321 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
322 | PRODUCT_BUNDLE_IDENTIFIER = com.ostatnicky.DraggableViewController;
323 | PRODUCT_NAME = "$(TARGET_NAME)";
324 | SWIFT_VERSION = 4.2;
325 | };
326 | name = Release;
327 | };
328 | /* End XCBuildConfiguration section */
329 |
330 | /* Begin XCConfigurationList section */
331 | 4B5F2C7F1CECAF590001CEFE /* Build configuration list for PBXProject "DraggableViewController" */ = {
332 | isa = XCConfigurationList;
333 | buildConfigurations = (
334 | 4B5F2C941CECAF5A0001CEFE /* Debug */,
335 | 4B5F2C951CECAF5A0001CEFE /* Release */,
336 | );
337 | defaultConfigurationIsVisible = 0;
338 | defaultConfigurationName = Release;
339 | };
340 | 4B5F2C961CECAF5A0001CEFE /* Build configuration list for PBXNativeTarget "DraggableViewController" */ = {
341 | isa = XCConfigurationList;
342 | buildConfigurations = (
343 | 4B5F2C971CECAF5A0001CEFE /* Debug */,
344 | 4B5F2C981CECAF5A0001CEFE /* Release */,
345 | );
346 | defaultConfigurationIsVisible = 0;
347 | defaultConfigurationName = Release;
348 | };
349 | /* End XCConfigurationList section */
350 | };
351 | rootObject = 4B5F2C7C1CECAF590001CEFE /* Project object */;
352 | }
353 |
--------------------------------------------------------------------------------