├── 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 | [![Swift](https://img.shields.io/badge/swift-4.x-orange.svg?style=flat)](https://swift.org/) [![Xcode](https://img.shields.io/badge/xcode-10.x-blue.svg?style=flat)](https://developer.apple.com/xcode/) 6 | 7 | ![DraggableViewController](/draggableViewController.gif "DraggableViewController") 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 | --------------------------------------------------------------------------------