├── AnimationExampleAdvanced ├── Assets.xcassets │ ├── Contents.json │ ├── close.imageset │ │ ├── Close.png │ │ ├── Close@2x.png │ │ ├── Close@3x.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── 1024.png │ │ ├── 114.png │ │ ├── 120.png │ │ ├── 180.png │ │ ├── 29.png │ │ ├── 40.png │ │ ├── 57.png │ │ ├── 58.png │ │ ├── 60.png │ │ ├── 80.png │ │ ├── 87.png │ │ └── Contents.json │ ├── bruce1.imageset │ │ ├── bruce1.png │ │ └── Contents.json │ ├── madonna.imageset │ │ ├── madonna.png │ │ └── Contents.json │ ├── kateperry.imageset │ │ ├── kateperry.png │ │ └── Contents.json │ ├── mjackson.imageset │ │ ├── mjackson.png │ │ └── Contents.json │ ├── profile1.imageset │ │ ├── profile1.png │ │ └── Contents.json │ ├── profile2.imageset │ │ ├── profile2.png │ │ └── Contents.json │ ├── profile3.imageset │ │ ├── profile3.png │ │ └── Contents.json │ ├── profile4.imageset │ │ ├── profile4.png │ │ └── Contents.json │ ├── PlusButton.imageset │ │ ├── PlusButton.png │ │ └── Contents.json │ ├── playButton.imageset │ │ ├── playButton.png │ │ └── Contents.json │ ├── 3dotsButton.imageset │ │ ├── 3dotsButton.png │ │ └── Contents.json │ ├── downloadButton.imageset │ │ ├── downloadButton.png │ │ └── Contents.json │ ├── handLikeButton.imageset │ │ ├── handLikeButton.png │ │ └── Contents.json │ └── forbiddenButton.imageset │ │ ├── forbiddenButton.png │ │ └── Contents.json ├── README.md ├── Info.plist ├── ViewController.swift ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── Common │ ├── Navigation │ │ └── TransitionCordinator.swift │ └── ViewControllerTransitions │ │ ├── PopAnimator.swift │ │ └── PushAnimator.swift ├── Views │ └── Cells │ │ ├── MainTableViewCell.swift │ │ └── MainTableViewCell.xib ├── Controllers │ ├── PushedViewController.swift │ ├── MainViewController+DataSource.swift │ ├── MainViewController.xib │ ├── MainViewController+ProtocolTransition.swift │ ├── MainViewController.swift │ └── PushedViewController.xib ├── AppDelegate.swift └── Helpers │ └── Helpers.swift └── AnimationExampleAdvanced.xcodeproj ├── project.xcworkspace ├── xcuserdata │ ├── fran.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── fobarrio.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── xcuserdata ├── fobarrio.xcuserdatad │ └── xcschemes │ │ └── xcschememanagement.plist └── fran.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── xcshareddata └── xcschemes │ └── AnimationExampleAdvanced.xcscheme └── project.pbxproj /AnimationExampleAdvanced/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/114.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/120.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/180.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/57.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/58.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/60.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/80.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/87.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/bruce1.imageset/bruce1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/bruce1.imageset/bruce1.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close@2x.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/close.imageset/Close@3x.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/madonna.imageset/madonna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/madonna.imageset/madonna.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/kateperry.imageset/kateperry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/kateperry.imageset/kateperry.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/mjackson.imageset/mjackson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/mjackson.imageset/mjackson.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile1.imageset/profile1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/profile1.imageset/profile1.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile2.imageset/profile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/profile2.imageset/profile2.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile3.imageset/profile3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/profile3.imageset/profile3.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile4.imageset/profile4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/profile4.imageset/profile4.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/PlusButton.imageset/PlusButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/PlusButton.imageset/PlusButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/playButton.imageset/playButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/playButton.imageset/playButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/3dotsButton.imageset/3dotsButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/3dotsButton.imageset/3dotsButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/downloadButton.imageset/downloadButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/downloadButton.imageset/downloadButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/handLikeButton.imageset/handLikeButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/handLikeButton.imageset/handLikeButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/forbiddenButton.imageset/forbiddenButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced/Assets.xcassets/forbiddenButton.imageset/forbiddenButton.png -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/project.xcworkspace/xcuserdata/fran.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced.xcodeproj/project.xcworkspace/xcuserdata/fran.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/project.xcworkspace/xcuserdata/fobarrio.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franobarrio/animation-transition-viewcontroller-advanced/HEAD/AnimationExampleAdvanced.xcodeproj/project.xcworkspace/xcuserdata/fobarrio.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/bruce1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "bruce1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/madonna.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "madonna.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/mjackson.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "mjackson.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "profile1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "profile2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "profile3.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/profile4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "profile4.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/PlusButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "PlusButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/kateperry.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "kateperry.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/playButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "playButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/3dotsButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "3dotsButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/downloadButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "downloadButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/forbiddenButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "forbiddenButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/handLikeButton.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "handLikeButton.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/xcuserdata/fobarrio.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AnimationExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/close.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Close.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Close@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "Close@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/xcuserdata/fran.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AnimationExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | AnimationExampleAdvanced.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | A19C219B21471E8600CDC6ED 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | 4 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com - https://twitter.com/fran_obarrio 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * 23 | * 24 | * Basically ... Feel Free to use this code as you want ! 25 | * BTW I'm available for freelance work :D 26 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]} -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | VC Animation II 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/ViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | class ViewController: UIViewController { 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | // Do any additional setup after loading the view, typically from a nib. 30 | } 31 | 32 | override func didReceiveMemoryWarning() { 33 | super.didReceiveMemoryWarning() 34 | // Dispose of any resources that can be recreated. 35 | } 36 | 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/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 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/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 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Common/Navigation/TransitionCordinator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | 26 | // NavigationController Delegate for Transition Coordinator 27 | class TransitionCoordinator: NSObject, UINavigationControllerDelegate { 28 | func navigationController(_ navigationController: UINavigationController, 29 | animationControllerFor operation: UINavigationControllerOperation, 30 | from fromVC: UIViewController, 31 | to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 32 | 33 | 34 | switch operation { 35 | case .push: 36 | //return PushAnimator() 37 | return PushAnimator(duration: TimeInterval(UINavigationControllerHideShowBarDuration)) 38 | case .pop: 39 | //return PopAnimator() 40 | return PopAnimator(duration: TimeInterval(UINavigationControllerHideShowBarDuration)) 41 | default: 42 | return nil 43 | } 44 | 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Views/Cells/MainTableViewCell.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | class MainTableViewCell: UITableViewCell { 26 | 27 | 28 | @IBOutlet weak var cellBackground: UIView! 29 | @IBOutlet weak var profileImageView: UIImageView! 30 | @IBOutlet weak var plusImageView: UIImageView! 31 | @IBOutlet weak var playImageView: UIImageView! 32 | @IBOutlet weak var likeImageView: UIImageView! 33 | @IBOutlet weak var cancelImageView: UIImageView! 34 | @IBOutlet weak var backgroundImageView: UIImageView! 35 | 36 | @IBOutlet weak var mainTitleLbl: UILabel! 37 | @IBOutlet weak var albumTitle: UILabel! 38 | @IBOutlet weak var albumYearLbl: UILabel! 39 | 40 | 41 | 42 | // MARK: Initialization 43 | fileprivate var stateCel:Int = 0 44 | 45 | required init?(coder aDecoder: NSCoder) { 46 | super.init(coder: aDecoder) 47 | 48 | } 49 | 50 | override func awakeFromNib() { 51 | super.awakeFromNib() 52 | 53 | setupView() 54 | 55 | } 56 | 57 | override func prepareForReuse() { 58 | super.prepareForReuse() 59 | } 60 | 61 | 62 | func setupCell(backgroundImage: String, profileImage: String, backgroundColor: String, title: String, album: String, year: String) { 63 | self.profileImageView.image = UIImage(named: profileImage) 64 | self.backgroundImageView.image = UIImage(named: backgroundImage) 65 | self.cellBackground.backgroundColor = backgroundColor.hexColor 66 | self.mainTitleLbl.text = title 67 | self.albumTitle.text = album 68 | self.albumYearLbl.text = year 69 | } 70 | 71 | func setupView() { 72 | 73 | self.cellBackground.layer.borderWidth = 0.0 74 | self.cellBackground.layer.borderColor = UIColor.clear.cgColor 75 | self.cellBackground.layer.cornerRadius = 10 76 | self.cellBackground.layer.masksToBounds = false 77 | 78 | self.selectionStyle = .none 79 | 80 | } 81 | 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/PushedViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | 4 | class PushedViewController: UIViewController { 5 | 6 | // ImageViews 7 | @IBOutlet weak var profileIV: UIImageView! 8 | @IBOutlet weak var plusIV: UIImageView! 9 | @IBOutlet weak var playIV: UIImageView! 10 | @IBOutlet weak var likeIV: UIImageView! 11 | @IBOutlet weak var cancelIV: UIImageView! 12 | @IBOutlet weak var backgroundIV: UIImageView! 13 | 14 | // Views 15 | @IBOutlet weak var topBackground: UIView! 16 | @IBOutlet weak var bottomBackground: UIView! 17 | 18 | // Labels 19 | @IBOutlet weak var titleLbl: UILabel! 20 | @IBOutlet weak var albumLabel: UILabel! 21 | @IBOutlet weak var yearLabel: UILabel! 22 | 23 | 24 | // Vars 25 | var selectedProfileImage: String? 26 | var selectedBackgroundImage: String? 27 | var mainTitle: String? 28 | var album: String? 29 | var year: String? 30 | var topHexColor: String? 31 | 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | 36 | if let topColor = topHexColor { 37 | topBackground.backgroundColor = topColor.hexColor 38 | } 39 | 40 | // Setup Profile Image 41 | if let imageProfile = selectedProfileImage { 42 | profileIV.image = UIImage(named: imageProfile) 43 | } 44 | 45 | // Setup Profile Image 46 | if let imageBackground = selectedBackgroundImage { 47 | backgroundIV.image = UIImage(named: imageBackground) 48 | } 49 | // Setup Title 50 | if let selectedTitle = mainTitle { 51 | self.titleLbl.text = selectedTitle 52 | } 53 | // Setup Album 54 | if let selectedAlbum = album { 55 | self.albumLabel.text = selectedAlbum 56 | } 57 | // Setup Year 58 | if let selectedYear = year { 59 | self.yearLabel.text = selectedYear 60 | } 61 | 62 | 63 | let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTapped)) 64 | self.view.addGestureRecognizer(tap) 65 | 66 | } 67 | 68 | @objc func doubleTapped() { 69 | self.navigationController?.popViewController(animated: true) 70 | } 71 | 72 | 73 | } 74 | 75 | extension PushedViewController : animTransitionable 76 | { 77 | var profileImageView: UIImageView { 78 | return profileIV 79 | } 80 | 81 | var backgroundImageView: UIImageView { 82 | return backgroundIV 83 | } 84 | 85 | var plusImageView: UIImageView { 86 | return plusIV 87 | } 88 | 89 | var playImageView: UIImageView { 90 | return playIV 91 | } 92 | 93 | var likeImageView: UIImageView { 94 | return likeIV 95 | } 96 | 97 | var cancelImageView: UIImageView { 98 | return cancelIV 99 | } 100 | 101 | var backgroundColor: UIView { 102 | return topBackground 103 | } 104 | 105 | var cellBackground: UIView { 106 | return bottomBackground 107 | } 108 | 109 | var bigTitle: UILabel { 110 | return titleLbl 111 | } 112 | 113 | var albumLbl: UILabel { 114 | return albumLabel 115 | } 116 | 117 | var yearLbl: UILabel { 118 | return yearLabel 119 | } 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/xcshareddata/xcschemes/AnimationExampleAdvanced.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | @UIApplicationMain 26 | class AppDelegate: UIResponder, UIApplicationDelegate { 27 | 28 | var window: UIWindow? 29 | 30 | //let transitionCoordinator = TransitionCoordinator() 31 | 32 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 33 | 34 | 35 | let whiteVC = MainViewController() 36 | 37 | window = UIWindow(frame: UIScreen.main.bounds) 38 | let nav = UINavigationController(rootViewController: whiteVC) 39 | nav.isNavigationBarHidden = true 40 | 41 | //Add TransitionCoordinator as navigation controller's delegate 42 | //nav.delegate = transitionCoordinator 43 | 44 | window?.rootViewController = nav 45 | window?.makeKeyAndVisible() 46 | 47 | // Override point for customization after application launch. 48 | return true 49 | } 50 | 51 | func applicationWillResignActive(_ application: UIApplication) { 52 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 53 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 54 | } 55 | 56 | func applicationDidEnterBackground(_ application: UIApplication) { 57 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 58 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 59 | } 60 | 61 | func applicationWillEnterForeground(_ application: UIApplication) { 62 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 63 | } 64 | 65 | func applicationDidBecomeActive(_ application: UIApplication) { 66 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 67 | } 68 | 69 | func applicationWillTerminate(_ application: UIApplication) { 70 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 71 | } 72 | 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/MainViewController+DataSource.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | // MARK: - DataSource 26 | extension MainViewController: UITableViewDataSource { 27 | 28 | 29 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 30 | 31 | let cell = tableView.dequeueReusableCell(withIdentifier: "mainCell") as! MainTableViewCell 32 | cell.setupCell(backgroundImage: dictionaryDataArray[indexPath.section]["backgroundImage"]!, 33 | profileImage: dictionaryDataArray[indexPath.section]["profileImage"]!, backgroundColor: dictionaryDataArray[indexPath.section]["hexBackgroundColor"]!, title: dictionaryDataArray[indexPath.section]["title"]!, album: dictionaryDataArray[indexPath.section]["album"]!, year: dictionaryDataArray[indexPath.section]["year"]!) 34 | 35 | return cell 36 | 37 | } 38 | 39 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 40 | 41 | self.selectedIndexPath = indexPath 42 | 43 | doAnimFadeOut() 44 | 45 | let finalVC = PushedViewController() 46 | finalVC.selectedProfileImage = dictionaryDataArray[indexPath.section]["profileImage"]! 47 | finalVC.selectedBackgroundImage = dictionaryDataArray[indexPath.section]["backgroundImage"]! 48 | finalVC.mainTitle = dictionaryDataArray[indexPath.section]["title"]! 49 | finalVC.album = dictionaryDataArray[indexPath.section]["album"]! 50 | finalVC.year = dictionaryDataArray[indexPath.section]["year"]! 51 | finalVC.topHexColor = dictionaryDataArray[indexPath.section]["hexBackgroundColor"]! 52 | 53 | 54 | navigationController?.delegate = transition 55 | 56 | DispatchQueue.main.asyncAfter(deadline: .now() + (Double(self.tableView.visibleCells.count) * 0.15 )) { // change 2 to desired number of seconds 57 | self.navigationController?.pushViewController(finalVC, animated: true) 58 | } 59 | 60 | 61 | } 62 | 63 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 64 | return UITableViewAutomaticDimension 65 | } 66 | 67 | func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { 68 | return UITableViewAutomaticDimension 69 | } 70 | 71 | func numberOfSections(in tableView: UITableView) -> Int { 72 | return dictionaryDataArray.count 73 | } 74 | 75 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 76 | return 1 77 | } 78 | 79 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 80 | return 20 81 | } 82 | 83 | //Let's insert a headerView to create the spacing we want 84 | func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 85 | let view = UIView() 86 | view.frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 20) //size of a standard tableViewCell 87 | view.backgroundColor = UIColor.clear 88 | return view 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/MainViewController.xib: -------------------------------------------------------------------------------- 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 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/MainViewController+ProtocolTransition.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | // MARK: - Protocol for Transition 26 | extension MainViewController : animTransitionable 27 | { 28 | 29 | // Profile Image 30 | var profileImageView: UIImageView { 31 | if let indexPath = selectedIndexPath { 32 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 33 | return cell.profileImageView 34 | } 35 | return UIImageView() 36 | } 37 | 38 | // Background Image 39 | var backgroundImageView: UIImageView { 40 | if let indexPath = selectedIndexPath { 41 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 42 | return cell.backgroundImageView 43 | } 44 | return UIImageView() 45 | } 46 | 47 | 48 | // Plus Button 49 | var plusImageView: UIImageView { 50 | if let indexPath = selectedIndexPath { 51 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 52 | return cell.plusImageView 53 | } 54 | return UIImageView() 55 | } 56 | 57 | // Play Button 58 | var playImageView: UIImageView { 59 | if let indexPath = selectedIndexPath { 60 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 61 | return cell.playImageView 62 | } 63 | return UIImageView() 64 | } 65 | 66 | // Like Button 67 | var likeImageView: UIImageView { 68 | if let indexPath = selectedIndexPath { 69 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 70 | return cell.likeImageView 71 | } 72 | return UIImageView() 73 | } 74 | 75 | // Cancel Button 76 | var cancelImageView: UIImageView { 77 | if let indexPath = selectedIndexPath { 78 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 79 | return cell.cancelImageView 80 | } 81 | return UIImageView() 82 | } 83 | 84 | 85 | 86 | // Background Color 87 | var backgroundColor: UIView { 88 | return backgroundView 89 | } 90 | 91 | // Cell Background 92 | var cellBackground: UIView { 93 | if let indexPath = selectedIndexPath { 94 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 95 | return cell.cellBackground 96 | } 97 | return UIView() 98 | } 99 | 100 | // Labels 101 | var bigTitle: UILabel { 102 | if let indexPath = selectedIndexPath { 103 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 104 | return cell.mainTitleLbl 105 | } 106 | return UILabel() 107 | } 108 | var albumLbl: UILabel { 109 | if let indexPath = selectedIndexPath { 110 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 111 | return cell.albumTitle 112 | } 113 | return UILabel() 114 | } 115 | var yearLbl: UILabel { 116 | if let indexPath = selectedIndexPath { 117 | let cell = tableView?.cellForRow(at: indexPath) as! MainTableViewCell 118 | return cell.albumYearLbl 119 | } 120 | return UILabel() 121 | } 122 | 123 | 124 | 125 | 126 | 127 | } 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/MainViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Francisco Obarrio - fobarrio@gmail.com 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import UIKit 24 | 25 | 26 | class MainViewController: UIViewController, UINavigationControllerDelegate, UITableViewDelegate { 27 | 28 | 29 | @IBOutlet weak var tableView: UITableView! 30 | @IBOutlet var backgroundView: UIView! 31 | 32 | 33 | let transition = TransitionCoordinator() 34 | 35 | var selectedIndexPath: IndexPath! 36 | 37 | // This is an array of dictionaries. 38 | var dictionaryDataArray: [[String: String]] = [ 39 | [ 40 | "profileImage": "profile1", 41 | "backgroundImage": "kateperry", 42 | "album": "One of the Boys", 43 | "year": "2003", 44 | "hexBackgroundColor": "d15d63", 45 | "title": "Kate Perry" 46 | ], 47 | [ 48 | "profileImage": "profile2", 49 | "backgroundImage": "bruce1", 50 | "album": "Born in the USA", 51 | "year": "1984", 52 | "hexBackgroundColor": "2d72b5", 53 | "title": "Bruce Springsteen" 54 | ], 55 | [ 56 | "profileImage": "profile3", 57 | "backgroundImage": "mjackson", 58 | "album": "Thriller", 59 | "year": "1982", 60 | "hexBackgroundColor": "fdeba9", 61 | "title": "Michael Jackson" 62 | ], 63 | 64 | [ 65 | "profileImage": "profile4", 66 | "backgroundImage": "madonna", 67 | "album": "Like a Prayer", 68 | "year": "1998", 69 | "hexBackgroundColor": "S1B733", 70 | "title": "Madonna" 71 | ] 72 | 73 | 74 | ] 75 | 76 | override func viewDidLoad() { 77 | super.viewDidLoad() 78 | 79 | self.tableView.register(UINib(nibName: "MainTableViewCell", bundle: nil), forCellReuseIdentifier: "mainCell") 80 | 81 | } 82 | 83 | override func didReceiveMemoryWarning() { 84 | super.didReceiveMemoryWarning() 85 | // Dispose of any resources that can be recreated. 86 | } 87 | 88 | override func viewDidAppear(_ animated: Bool) { 89 | super.viewDidAppear(animated) 90 | 91 | if let transitionCoordinator = navigationController?.transitionCoordinator, 92 | let fromVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.from), 93 | let toVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.to), 94 | fromVC is PushedViewController, 95 | toVC is MainViewController { 96 | 97 | doAnimFadeIn() 98 | 99 | } 100 | } 101 | 102 | func doAnimFadeIn() { 103 | 104 | let cells = self.tableView.indexPathsForVisibleRows 105 | var index = 0 106 | 107 | if let cells = cells, cells.count > 0 { 108 | for x in 0.. 0 { 128 | for x in 0..> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) 55 | case 6: // RGB (24-bit) 56 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) 57 | case 8: // ARGB (32-bit) 58 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) 59 | default: 60 | return .clear 61 | } 62 | return UIColor(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255) 63 | } 64 | } 65 | 66 | func attributedString(from string: String, lineSpacing: CGFloat = 1.0, font: UIFont, fontColor: UIColor = UIColor.black, alignment: NSTextAlignment = .natural, kerning: CGFloat = 1.0) -> NSMutableAttributedString { 67 | 68 | let style = NSMutableParagraphStyle() 69 | style.lineSpacing = lineSpacing 70 | style.alignment = alignment 71 | 72 | let attrs = [ 73 | NSAttributedStringKey.font: font, 74 | NSAttributedStringKey.foregroundColor: fontColor, 75 | NSAttributedStringKey.paragraphStyle: style, 76 | NSAttributedStringKey.kern: kerning 77 | ] as [NSAttributedStringKey : Any] 78 | 79 | let attrStr = NSMutableAttributedString(string: string, attributes: attrs) 80 | 81 | return attrStr 82 | } 83 | 84 | func addParabolaWithMax(maxPoint: CGPoint, inRect boundingRect: CGRect) -> UIBezierPath { 85 | 86 | func halfPoint1D(p0: CGFloat, p2: CGFloat, control: CGFloat) -> CGFloat { 87 | return 2 * control - p0 / 2 - p2 / 2 88 | } 89 | 90 | let path = UIBezierPath() 91 | 92 | let p0 = CGPoint(x: 0, y: boundingRect.maxY) 93 | let p2 = CGPoint(x: boundingRect.maxX, y: boundingRect.maxY) 94 | 95 | let p1 = CGPoint(x: halfPoint1D(p0: p0.x, p2: p2.x, control: maxPoint.x), 96 | y: halfPoint1D(p0: p0.y, p2: p2.y, control: maxPoint.y)) 97 | 98 | path.move(to: p0) 99 | path.addQuadCurve(to: p2, controlPoint: p1) 100 | return path 101 | } 102 | 103 | func duplicateLabel(label: UILabel) -> UILabel { 104 | let newLabel = UILabel(frame: label.frame) 105 | newLabel.font = label.font 106 | newLabel.textAlignment = label.textAlignment 107 | newLabel.textColor = label.textColor 108 | newLabel.backgroundColor = label.backgroundColor 109 | 110 | //newLabel.adjustsFontSizeToFitWidth = true 111 | 112 | return newLabel 113 | } 114 | 115 | extension UIFont { 116 | 117 | /** 118 | Will return the best font conforming to the descriptor which will fit in the provided bounds. 119 | */ 120 | static func bestFittingFontSize(for text: String, in bounds: CGRect, fontDescriptor: UIFontDescriptor, additionalAttributes: [NSAttributedStringKey: Any]? = nil) -> CGFloat { 121 | let constrainingDimension = min(bounds.width, bounds.height) 122 | let properBounds = CGRect(origin: .zero, size: bounds.size) 123 | var attributes = additionalAttributes ?? [:] 124 | 125 | let infiniteBounds = CGSize(width: CGFloat.infinity, height: CGFloat.infinity) 126 | var bestFontSize: CGFloat = constrainingDimension 127 | 128 | for fontSize in stride(from: bestFontSize, through: 0, by: -1) { 129 | let newFont = UIFont(descriptor: fontDescriptor, size: fontSize) 130 | attributes[.font] = newFont 131 | 132 | let currentFrame = text.boundingRect(with: infiniteBounds, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: attributes, context: nil) 133 | 134 | if properBounds.contains(currentFrame) { 135 | bestFontSize = fontSize 136 | break 137 | } 138 | } 139 | return bestFontSize 140 | } 141 | 142 | static func bestFittingFont(for text: String, in bounds: CGRect, fontDescriptor: UIFontDescriptor, additionalAttributes: [NSAttributedStringKey: Any]? = nil) -> UIFont { 143 | let bestSize = bestFittingFontSize(for: text, in: bounds, fontDescriptor: fontDescriptor, additionalAttributes: additionalAttributes) 144 | return UIFont(descriptor: fontDescriptor, size: bestSize) 145 | } 146 | } 147 | 148 | extension UILabel { 149 | 150 | /// Will auto resize the contained text to a font size which fits the frames bounds. 151 | /// Uses the pre-set font to dynamically determine the proper sizing 152 | func fitTextToBounds() { 153 | guard let text = text, let currentFont = font else { return } 154 | 155 | let bestFittingFont = UIFont.bestFittingFont(for: text, in: bounds, fontDescriptor: currentFont.fontDescriptor, additionalAttributes: basicStringAttributes) 156 | font = bestFittingFont 157 | } 158 | 159 | private var basicStringAttributes: [NSAttributedStringKey: Any] { 160 | var attribs = [NSAttributedStringKey: Any]() 161 | 162 | let paragraphStyle = NSMutableParagraphStyle() 163 | paragraphStyle.alignment = self.textAlignment 164 | paragraphStyle.lineBreakMode = self.lineBreakMode 165 | attribs[.paragraphStyle] = paragraphStyle 166 | 167 | return attribs 168 | } 169 | } 170 | 171 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Views/Cells/MainTableViewCell.xib: -------------------------------------------------------------------------------- 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 | 38 | 45 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Common/ViewControllerTransitions/PopAnimator.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import QuartzCore 3 | 4 | 5 | class PopAnimator: NSObject, UIViewControllerAnimatedTransitioning { 6 | 7 | var duration : TimeInterval 8 | 9 | init(duration : TimeInterval) { 10 | self.duration = duration 11 | } 12 | 13 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 14 | return duration 15 | } 16 | 17 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 18 | 19 | let containerView = transitionContext.containerView 20 | 21 | 22 | guard let fromVC = transitionContext.viewController(forKey: .from) as? animTransitionable, 23 | let toVC = transitionContext.viewController(forKey: .to) as? animTransitionable else { 24 | transitionContext.completeTransition(false) 25 | return 26 | } 27 | 28 | 29 | 30 | 31 | let fromViewController = transitionContext.viewController(forKey: .from)! 32 | let toViewController = transitionContext.viewController(forKey: .to)! 33 | 34 | // Plus Image 35 | let imageViewSnapshotPlus = UIImageView(image: fromVC.plusImageView.image) 36 | imageViewSnapshotPlus.contentMode = .scaleAspectFit 37 | 38 | //Profile Image 39 | let imageViewSnapshotProfile = UIImageView(image: fromVC.profileImageView.image) 40 | imageViewSnapshotProfile.contentMode = .scaleAspectFit 41 | 42 | //Background Image 43 | let imageViewSnapshotBackground = UIImageView(image: fromVC.backgroundImageView.image) 44 | imageViewSnapshotBackground.contentMode = .scaleAspectFit 45 | 46 | 47 | //Like Image 48 | let imageViewSnapshotLike = UIImageView(image: fromVC.likeImageView.image) 49 | imageViewSnapshotLike.contentMode = .scaleAspectFit 50 | 51 | //Play Image 52 | let imageViewSnapshotPlay = UIImageView(image: fromVC.playImageView.image) 53 | imageViewSnapshotPlay.contentMode = .scaleAspectFit 54 | 55 | //Cancel Image 56 | let imageViewSnapshotCancel = UIImageView(image: fromVC.cancelImageView.image) 57 | imageViewSnapshotCancel.contentMode = .scaleAspectFit 58 | 59 | 60 | 61 | //Background View With Correct Color 62 | let backgroundView = UIView() 63 | backgroundView.frame = fromVC.backgroundColor.frame 64 | backgroundView.backgroundColor = UIColor.white 65 | containerView.addSubview(backgroundView) 66 | 67 | 68 | // Title 69 | let titleLabel = duplicateLabel(label: fromVC.bigTitle) 70 | titleLabel.text = fromVC.bigTitle.text 71 | titleLabel.backgroundColor = UIColor.clear 72 | titleLabel.frame = containerView.convert(fromVC.bigTitle.frame, from: fromVC.bigTitle.superview) 73 | titleLabel.sizeToFit() 74 | 75 | // Album 76 | let albumLabel = duplicateLabel(label: fromVC.albumLbl) 77 | albumLabel.text = fromVC.albumLbl.text 78 | albumLabel.backgroundColor = UIColor.clear 79 | albumLabel.frame = containerView.convert(fromVC.albumLbl.frame, from: fromVC.albumLbl.superview) 80 | albumLabel.sizeToFit() 81 | 82 | 83 | // Year 84 | let yearLabel = duplicateLabel(label: fromVC.yearLbl) 85 | yearLabel.text = fromVC.yearLbl.text 86 | yearLabel.backgroundColor = UIColor.clear 87 | yearLabel.frame = containerView.convert(fromVC.yearLbl.frame, from: fromVC.yearLbl.superview) 88 | yearLabel.sizeToFit() 89 | 90 | 91 | 92 | 93 | // Cell Background 94 | let cellBackground = UIView() 95 | cellBackground.backgroundColor = fromVC.backgroundColor.backgroundColor 96 | cellBackground.layer.cornerRadius = fromVC.backgroundColor.layer.cornerRadius 97 | cellBackground.layer.masksToBounds = fromVC.backgroundColor.layer.masksToBounds 98 | cellBackground.frame = containerView.convert(fromVC.backgroundColor.frame, from: fromVC.backgroundColor.superview) 99 | cellBackground.setNeedsLayout() 100 | 101 | 102 | containerView.addSubview(fromViewController.view) 103 | containerView.addSubview(toViewController.view) 104 | 105 | containerView.addSubview(cellBackground) 106 | 107 | 108 | 109 | 110 | 111 | // Top 112 | containerView.addSubview(imageViewSnapshotProfile) 113 | containerView.addSubview(imageViewSnapshotBackground) 114 | containerView.addSubview(imageViewSnapshotPlus) 115 | 116 | // Down 117 | containerView.addSubview(imageViewSnapshotCancel) 118 | containerView.addSubview(imageViewSnapshotPlay) 119 | containerView.addSubview(imageViewSnapshotLike) 120 | 121 | 122 | // Title Label 123 | containerView.addSubview(titleLabel) 124 | containerView.addSubview(albumLabel) 125 | containerView.addSubview(yearLabel) 126 | 127 | 128 | 129 | 130 | 131 | containerView.bringSubview(toFront: imageViewSnapshotPlus) 132 | 133 | 134 | fromViewController.view.isHidden = true 135 | toViewController.view.isHidden = true 136 | 137 | // TOP 138 | imageViewSnapshotPlus.frame = containerView.convert(fromVC.plusImageView.frame, from: fromVC.plusImageView.superview) 139 | imageViewSnapshotProfile.frame = containerView.convert(fromVC.profileImageView.frame, from: fromVC.profileImageView.superview) 140 | imageViewSnapshotBackground.frame = containerView.convert(fromVC.backgroundImageView.frame, from: fromVC.backgroundImageView.superview) 141 | 142 | 143 | // BOTTOM 144 | imageViewSnapshotCancel.frame = containerView.convert(fromVC.cancelImageView.frame, from: fromVC.cancelImageView.superview) 145 | imageViewSnapshotPlay.frame = containerView.convert(fromVC.playImageView.frame, from: fromVC.playImageView.superview) 146 | imageViewSnapshotLike.frame = containerView.convert(fromVC.likeImageView.frame, from: fromVC.likeImageView.superview) 147 | 148 | 149 | 150 | 151 | let frameBackground: CGRect = containerView.convert(toVC.cellBackground.frame, from: toVC.cellBackground.superview) 152 | 153 | // TOP 154 | let frameProfile: CGRect = containerView.convert(toVC.profileImageView.frame, from: toVC.profileImageView.superview) 155 | let frameBackgroundImage: CGRect = containerView.convert(toVC.backgroundImageView.frame, from: toVC.backgroundImageView.superview) 156 | let framePlus: CGRect = containerView.convert(toVC.plusImageView.frame, from: toVC.plusImageView.superview) 157 | 158 | // BOTTOM 159 | let framePlay: CGRect = containerView.convert(toVC.playImageView.frame, from: toVC.playImageView.superview) 160 | 161 | 162 | 163 | // Animators 164 | let animator1 = { 165 | UIViewPropertyAnimator(duration: 0.4, dampingRatio: 0.8) { 166 | 167 | // HAY QUE PONER BIEN LOS TAMAÑOS DE LAS IMAGENES 168 | 169 | let backgroundX = cellBackground.frame.minX + (cellBackground.frame.width * 5 / 100) 170 | let backgroundWidth = cellBackground.frame.width - (cellBackground.frame.width * 10 / 100) 171 | 172 | // BACKGROUND 173 | cellBackground.frame = frameBackground 174 | cellBackground.layer.cornerRadius = toVC.cellBackground.layer.cornerRadius 175 | 176 | 177 | // Label 178 | titleLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 179 | titleLabel.frame = containerView.convert(toVC.bigTitle.frame, from: toVC.bigTitle.superview) 180 | 181 | //albumLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 182 | albumLabel.frame = containerView.convert(toVC.albumLbl.frame, from: toVC.albumLbl.superview) 183 | albumLabel.textAlignment = .left 184 | 185 | //yearLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 186 | yearLabel.frame = containerView.convert(toVC.yearLbl.frame, from: toVC.yearLbl.superview) 187 | yearLabel.textAlignment = .left 188 | 189 | 190 | imageViewSnapshotCancel.frame = containerView.convert(toVC.cancelImageView.frame, from: toVC.cancelImageView.superview) 191 | imageViewSnapshotPlay.frame = containerView.convert(toVC.playImageView.frame, from: toVC.playImageView.superview) 192 | imageViewSnapshotLike.frame = containerView.convert(toVC.likeImageView.frame, from: toVC.likeImageView.superview) 193 | 194 | imageViewSnapshotBackground.frame = containerView.convert(toVC.backgroundImageView.frame, from: toVC.backgroundImageView.superview) 195 | 196 | 197 | } 198 | }() 199 | 200 | // Animators 201 | let animator2 = { 202 | //UIViewPropertyAnimator(duration: 0.5, dampingRatio: 0.6) { 203 | UIViewPropertyAnimator(duration: 0.2, curve: .easeOut) { 204 | cellBackground.frame = frameBackground 205 | cellBackground.layer.cornerRadius = toVC.cellBackground.layer.cornerRadius 206 | } 207 | }() 208 | 209 | 210 | 211 | 212 | animator1.addCompletion { _ in 213 | 214 | 215 | cellBackground.removeFromSuperview() 216 | fromViewController.view.removeFromSuperview() 217 | 218 | titleLabel.removeFromSuperview() 219 | albumLabel.removeFromSuperview() 220 | yearLabel.removeFromSuperview() 221 | 222 | // TOP 223 | imageViewSnapshotProfile.removeFromSuperview() 224 | imageViewSnapshotPlus.removeFromSuperview() 225 | imageViewSnapshotBackground.removeFromSuperview() 226 | 227 | // BOTTOM 228 | imageViewSnapshotCancel.removeFromSuperview() 229 | imageViewSnapshotPlay.removeFromSuperview() 230 | imageViewSnapshotLike.removeFromSuperview() 231 | 232 | 233 | toViewController.view.isHidden = false 234 | 235 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 236 | 237 | 238 | } 239 | 240 | 241 | animator2.addCompletion { _ in 242 | 243 | 244 | cellBackground.removeFromSuperview() 245 | fromViewController.view.removeFromSuperview() 246 | 247 | titleLabel.removeFromSuperview() 248 | albumLabel.removeFromSuperview() 249 | yearLabel.removeFromSuperview() 250 | 251 | // TOP 252 | imageViewSnapshotProfile.removeFromSuperview() 253 | imageViewSnapshotPlus.removeFromSuperview() 254 | imageViewSnapshotBackground.removeFromSuperview() 255 | 256 | // BOTTOM 257 | imageViewSnapshotCancel.removeFromSuperview() 258 | imageViewSnapshotPlay.removeFromSuperview() 259 | imageViewSnapshotLike.removeFromSuperview() 260 | 261 | //toViewController.view.removeFromSuperview() 262 | fromViewController.view.removeFromSuperview() 263 | 264 | toViewController.view.isHidden = false 265 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 266 | //transitionContext.completeTransition(true) 267 | } 268 | 269 | 270 | 271 | 272 | func doBezierAnimation(showLayerAnimation: Bool = false) { 273 | 274 | 275 | //*** PROFILE IMAGE ***// 276 | 277 | // Main ImageView Animation 278 | var bezierPath = UIBezierPath() 279 | bezierPath.move(to: CGPoint(x: imageViewSnapshotProfile.frame.midX, y: imageViewSnapshotProfile.frame.midY)) 280 | bezierPath.addQuadCurve(to: CGPoint(x: frameProfile.midX, y: frameProfile.midY), controlPoint: CGPoint(x: frameProfile.midX/2, y: frameProfile.midY/2)) 281 | 282 | 283 | var shapeLayer = CAShapeLayer() 284 | // The Bezier path that we made needs to be converted to a CGPath before it can be used on a layer. 285 | shapeLayer.path = bezierPath.cgPath 286 | shapeLayer.strokeColor = UIColor.blue.cgColor 287 | shapeLayer.fillColor = UIColor.clear.cgColor 288 | shapeLayer.lineWidth = 1.0 289 | 290 | // Enable/Disable for debug 291 | if showLayerAnimation { 292 | containerView.layer.addSublayer(shapeLayer) 293 | } 294 | 295 | let profileAnimationPosition = CAKeyframeAnimation(keyPath: "position") 296 | profileAnimationPosition.path = bezierPath.cgPath 297 | // I set this one to make the animation go smoothly along the path 298 | profileAnimationPosition.calculationMode = kCAAnimationPaced 299 | profileAnimationPosition.duration = 0.4 300 | profileAnimationPosition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 301 | 302 | 303 | let profileAnimationBounds = CAKeyframeAnimation(keyPath: "bounds") 304 | profileAnimationBounds.duration = 0.4 305 | profileAnimationBounds.values = [imageViewSnapshotProfile.frame, containerView.convert(toVC.profileImageView.frame, from: toVC.profileImageView.superview)] 306 | profileAnimationBounds.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 307 | profileAnimationBounds.beginTime = 0 308 | 309 | // Let's group the animation for position and bounds into one 310 | let groupProfile = CAAnimationGroup() 311 | groupProfile.animations = [profileAnimationPosition, profileAnimationBounds] 312 | groupProfile.duration = 0.4 313 | groupProfile.repeatCount = 0 314 | groupProfile.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 315 | groupProfile.isRemovedOnCompletion = false 316 | groupProfile.fillMode = kCAFillModeForwards 317 | 318 | imageViewSnapshotProfile.layer.add(groupProfile, forKey: "profileAnimation") 319 | 320 | 321 | //*** PLUS IMAGE ***// 322 | 323 | // Plus ImageView Animation 324 | bezierPath = UIBezierPath() 325 | bezierPath.move(to: CGPoint(x: imageViewSnapshotPlus.frame.midX, y: imageViewSnapshotPlus.frame.midY)) 326 | bezierPath.addQuadCurve(to: CGPoint(x: framePlus.midX, y: framePlus.midY), controlPoint: CGPoint(x:framePlus.maxX + 30, y: framePlus.maxY/4)) 327 | 328 | 329 | shapeLayer = CAShapeLayer() 330 | 331 | // The Bezier path that we made needs to be converted to a CGPath before it can be used on a layer. 332 | shapeLayer.path = bezierPath.cgPath 333 | shapeLayer.strokeColor = UIColor.blue.cgColor 334 | shapeLayer.fillColor = UIColor.clear.cgColor 335 | shapeLayer.lineWidth = 1.0 336 | 337 | // Enable/Disable for debug 338 | if showLayerAnimation { 339 | containerView.layer.addSublayer(shapeLayer) 340 | } 341 | 342 | 343 | 344 | let plusAnimationPosition = CAKeyframeAnimation(keyPath: "position") 345 | plusAnimationPosition.path = bezierPath.cgPath 346 | // I set this one to make the animation go smoothly along the path 347 | plusAnimationPosition.calculationMode = kCAAnimationPaced 348 | plusAnimationPosition.duration = 0.4 349 | plusAnimationPosition.rotationMode = kCAAnimationLinear 350 | plusAnimationPosition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 351 | 352 | 353 | let plusAnimationBounds = CAKeyframeAnimation(keyPath: "bounds") 354 | plusAnimationBounds.duration = 0.4 355 | plusAnimationBounds.values = [imageViewSnapshotPlus.frame, containerView.convert(toVC.plusImageView.frame, from: toVC.plusImageView.superview)] 356 | plusAnimationBounds.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 357 | plusAnimationBounds.beginTime = 0 358 | 359 | // Let's group the animation for position and bounds into one 360 | let groupPlus = CAAnimationGroup() 361 | groupPlus.animations = [plusAnimationPosition, plusAnimationBounds] 362 | groupPlus.duration = 0.4 363 | groupPlus.repeatCount = 0 364 | groupPlus.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 365 | groupPlus.isRemovedOnCompletion = false 366 | groupPlus.fillMode = kCAFillModeForwards 367 | 368 | imageViewSnapshotPlus.layer.add(groupPlus, forKey: "doit") 369 | 370 | 371 | 372 | 373 | } 374 | 375 | 376 | 377 | 378 | animator1.startAnimation() 379 | 380 | // Group Animator 381 | doBezierAnimation(showLayerAnimation: false) 382 | 383 | 384 | } 385 | 386 | 387 | } 388 | 389 | 390 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Controllers/PushedViewController.xib: -------------------------------------------------------------------------------- 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 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 123 | 133 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced/Common/ViewControllerTransitions/PushAnimator.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import QuartzCore 3 | 4 | 5 | class PushAnimator: NSObject, UIViewControllerAnimatedTransitioning { 6 | 7 | var duration : TimeInterval 8 | 9 | init(duration : TimeInterval) { 10 | self.duration = duration 11 | } 12 | 13 | func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 14 | return duration 15 | } 16 | 17 | func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 18 | 19 | let containerView = transitionContext.containerView 20 | 21 | 22 | guard let fromVC = transitionContext.viewController(forKey: .from) as? animTransitionable, 23 | let toVC = transitionContext.viewController(forKey: .to) as? animTransitionable else { 24 | transitionContext.completeTransition(false) 25 | return 26 | } 27 | 28 | 29 | 30 | 31 | let fromViewController = transitionContext.viewController(forKey: .from)! 32 | let toViewController = transitionContext.viewController(forKey: .to)! 33 | 34 | // Plus Image 35 | let imageViewSnapshotPlus = UIImageView(image: fromVC.plusImageView.image) 36 | imageViewSnapshotPlus.contentMode = .scaleAspectFit 37 | 38 | //Profile Image 39 | let imageViewSnapshotProfile = UIImageView(image: fromVC.profileImageView.image) 40 | imageViewSnapshotProfile.contentMode = .scaleAspectFit 41 | 42 | //Background Image 43 | let imageViewSnapshotBackground = UIImageView(image: fromVC.backgroundImageView.image) 44 | imageViewSnapshotBackground.contentMode = .scaleAspectFit 45 | 46 | 47 | //Like Image 48 | let imageViewSnapshotLike = UIImageView(image: fromVC.likeImageView.image) 49 | imageViewSnapshotLike.contentMode = .scaleAspectFit 50 | 51 | //Play Image 52 | let imageViewSnapshotPlay = UIImageView(image: fromVC.playImageView.image) 53 | imageViewSnapshotPlay.contentMode = .scaleAspectFit 54 | 55 | //Cancel Image 56 | let imageViewSnapshotCancel = UIImageView(image: fromVC.cancelImageView.image) 57 | imageViewSnapshotCancel.contentMode = .scaleAspectFit 58 | 59 | 60 | 61 | //Background View With Correct Color 62 | let backgroundView = UIView() 63 | backgroundView.frame = fromVC.backgroundColor.frame 64 | backgroundView.backgroundColor = UIColor.white 65 | containerView.addSubview(backgroundView) 66 | 67 | 68 | // Title 69 | let titleLabel = duplicateLabel(label: fromVC.bigTitle) 70 | titleLabel.text = fromVC.bigTitle.text 71 | titleLabel.backgroundColor = UIColor.clear 72 | titleLabel.frame = containerView.convert(fromVC.bigTitle.frame, from: fromVC.bigTitle.superview) 73 | 74 | // Album 75 | let albumLabel = duplicateLabel(label: fromVC.albumLbl) 76 | albumLabel.text = fromVC.albumLbl.text 77 | albumLabel.backgroundColor = UIColor.clear 78 | albumLabel.frame = containerView.convert(fromVC.albumLbl.frame, from: fromVC.albumLbl.superview) 79 | 80 | 81 | // Year 82 | let yearLabel = duplicateLabel(label: fromVC.yearLbl) 83 | yearLabel.text = fromVC.yearLbl.text 84 | yearLabel.backgroundColor = UIColor.clear 85 | yearLabel.frame = containerView.convert(fromVC.yearLbl.frame, from: fromVC.yearLbl.superview) 86 | 87 | 88 | 89 | 90 | // Cell Background 91 | let cellBackground = UIView() 92 | cellBackground.frame = containerView.convert(fromVC.cellBackground.frame, from: fromVC.cellBackground.superview) 93 | cellBackground.backgroundColor = fromVC.cellBackground.backgroundColor 94 | cellBackground.layer.cornerRadius = fromVC.cellBackground.layer.cornerRadius 95 | cellBackground.layer.masksToBounds = fromVC.cellBackground.layer.masksToBounds 96 | 97 | 98 | containerView.addSubview(fromViewController.view) 99 | containerView.addSubview(toViewController.view) 100 | 101 | // Background Cell 102 | containerView.addSubview(cellBackground) 103 | 104 | // Top 105 | containerView.addSubview(imageViewSnapshotProfile) 106 | containerView.addSubview(imageViewSnapshotBackground) 107 | containerView.addSubview(imageViewSnapshotPlus) 108 | 109 | // Down 110 | containerView.addSubview(imageViewSnapshotPlay) 111 | containerView.addSubview(imageViewSnapshotCancel) 112 | containerView.addSubview(imageViewSnapshotLike) 113 | 114 | 115 | // Title Label 116 | containerView.addSubview(titleLabel) 117 | containerView.addSubview(albumLabel) 118 | containerView.addSubview(yearLabel) 119 | 120 | containerView.bringSubview(toFront: imageViewSnapshotPlus) 121 | 122 | 123 | fromViewController.view.isHidden = true 124 | toViewController.view.isHidden = true 125 | 126 | // TOP 127 | imageViewSnapshotPlus.frame = containerView.convert(fromVC.plusImageView.frame, from: fromVC.plusImageView.superview) 128 | imageViewSnapshotProfile.frame = containerView.convert(fromVC.profileImageView.frame, from: fromVC.profileImageView.superview) 129 | imageViewSnapshotBackground.frame = containerView.convert(fromVC.backgroundImageView.frame, from: fromVC.backgroundImageView.superview) 130 | 131 | 132 | // BOTTOM 133 | imageViewSnapshotCancel.frame = containerView.convert(fromVC.cancelImageView.frame, from: fromVC.cancelImageView.superview) 134 | imageViewSnapshotPlay.frame = containerView.convert(fromVC.playImageView.frame, from: fromVC.playImageView.superview) 135 | imageViewSnapshotLike.frame = containerView.convert(fromVC.likeImageView.frame, from: fromVC.likeImageView.superview) 136 | 137 | 138 | 139 | 140 | let frameBackground: CGRect = containerView.convert(toVC.backgroundColor.frame, from: toVC.backgroundColor.superview) 141 | 142 | // TOP 143 | let frameProfile: CGRect = containerView.convert(toVC.profileImageView.frame, from: toVC.profileImageView.superview) 144 | let frameBackgroundImage: CGRect = containerView.convert(toVC.backgroundImageView.frame, from: toVC.backgroundImageView.superview) 145 | let framePlus: CGRect = containerView.convert(toVC.plusImageView.frame, from: toVC.plusImageView.superview) 146 | 147 | // BOTTOM 148 | let framePlay: CGRect = containerView.convert(toVC.playImageView.frame, from: toVC.playImageView.superview) 149 | 150 | 151 | // Animators 152 | let animator1 = { 153 | UIViewPropertyAnimator(duration: 0.5, dampingRatio: 0.8) { 154 | 155 | // HAY QUE PONER BIEN LOS TAMAÑOS DE LAS IMAGENES 156 | let backgroundX = cellBackground.frame.minX + (cellBackground.frame.width * 5 / 100) 157 | let backgroundWidth = cellBackground.frame.width - (cellBackground.frame.width * 10 / 100) 158 | 159 | 160 | // BACKGROUND 161 | cellBackground.frame = CGRect(x: backgroundX , y: cellBackground.frame.minY + (cellBackground.frame.minY * 5 / 100), width: backgroundWidth, height: cellBackground.frame.height - (cellBackground.frame.height * 10 / 100)) 162 | 163 | // LABEL 164 | titleLabel.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) 165 | titleLabel.frame = CGRect(x: titleLabel.frame.minX , y: titleLabel.frame.minY + 15, width: titleLabel.frame.width, height: titleLabel.frame.height) 166 | 167 | 168 | 169 | 170 | // TOP 171 | imageViewSnapshotPlus.frame = CGRect(x: cellBackground.frame.maxX - (imageViewSnapshotPlus.frame.width * 20 / 100) - 40 , y: cellBackground.frame.minY + (imageViewSnapshotPlus.frame.height * 20 / 100) + 10, width: imageViewSnapshotPlus.frame.width - (imageViewSnapshotPlus.frame.width * 20 / 100), height: imageViewSnapshotPlus.frame.height - (imageViewSnapshotPlus.frame.height * 20 / 100)) 172 | 173 | 174 | imageViewSnapshotProfile.frame = CGRect(x: cellBackground.frame.minX - (imageViewSnapshotProfile.frame.width * 20 / 100) + 30 , y: cellBackground.frame.minY + (imageViewSnapshotProfile.frame.height * 20 / 100) + 10, width: imageViewSnapshotProfile.frame.width - (imageViewSnapshotProfile.frame.width * 20 / 100), height: imageViewSnapshotProfile.frame.height - (imageViewSnapshotProfile.frame.height * 20 / 100)) 175 | 176 | // LAbels 177 | albumLabel.frame = CGRect(x: imageViewSnapshotProfile.frame.maxX + 15 , y: imageViewSnapshotProfile.frame.minY + 3, width: albumLabel.frame.width, height: albumLabel.frame.height) 178 | albumLabel.sizeToFit() 179 | 180 | yearLabel.frame = CGRect(x: imageViewSnapshotProfile.frame.maxX + 15 , y: imageViewSnapshotProfile.frame.minY + 23, width: yearLabel.frame.width, height: yearLabel.frame.height) 181 | yearLabel.sizeToFit() 182 | 183 | 184 | // Image Background 185 | let widthBackground = (imageViewSnapshotBackground.frame.width - (imageViewSnapshotBackground.frame.width * 20 / 100) ) 186 | let heightBackground = (imageViewSnapshotBackground.frame.height - (imageViewSnapshotBackground.frame.height * 20 / 100) ) 187 | let midPostionPlayButton = imageViewSnapshotPlay.frame.width - (imageViewSnapshotPlay.frame.width * 20 / 100) 188 | 189 | imageViewSnapshotBackground.frame = CGRect(x: cellBackground.frame.midX - (widthBackground / 2) , y: cellBackground.frame.maxY - (heightBackground) , width: widthBackground, height: imageViewSnapshotBackground.frame.height - (imageViewSnapshotBackground.frame.height * 20 / 100)) 190 | 191 | 192 | 193 | imageViewSnapshotPlay.frame = CGRect(x: cellBackground.frame.midX - (midPostionPlayButton / 2), y: cellBackground.frame.maxY - imageViewSnapshotPlay.frame.height - 10, width: imageViewSnapshotPlay.frame.width - (imageViewSnapshotPlay.frame.width * 20 / 100), height: imageViewSnapshotPlay.frame.width - (imageViewSnapshotPlay.frame.width * 20 / 100)) 194 | 195 | 196 | 197 | imageViewSnapshotCancel.frame = CGRect(x: cellBackground.frame.midX - (midPostionPlayButton / 2) - imageViewSnapshotCancel.frame.width - 30, y: cellBackground.frame.maxY - (imageViewSnapshotCancel.frame.height * 2), width: imageViewSnapshotCancel.frame.width - (imageViewSnapshotCancel.frame.width * 20 / 100), height: imageViewSnapshotCancel.frame.height - (imageViewSnapshotCancel.frame.height * 20 / 100)) 198 | 199 | imageViewSnapshotLike.frame = CGRect(x: cellBackground.frame.midX + (midPostionPlayButton / 2) + (imageViewSnapshotLike.frame.width * 20 / 100) + 30, y: cellBackground.frame.maxY - (imageViewSnapshotLike.frame.height * 2) , width: imageViewSnapshotLike.frame.width - (imageViewSnapshotLike.frame.width * 20 / 100), height: imageViewSnapshotLike.frame.height - (imageViewSnapshotLike.frame.height * 20 / 100)) 200 | 201 | 202 | 203 | } 204 | }() 205 | 206 | // Animators 207 | let animator2 = { 208 | //UIViewPropertyAnimator(duration: 0.5, dampingRatio: 0.6) { 209 | UIViewPropertyAnimator(duration: 0.3, curve: .easeOut) { 210 | 211 | cellBackground.frame = CGRect(x: frameBackground.minX , y: frameBackground.minY, width: UIScreen.main.bounds.width, height: frameBackground.height) 212 | cellBackground.layer.cornerRadius = 0 213 | 214 | // Label 215 | titleLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 216 | titleLabel.frame = containerView.convert(toVC.bigTitle.frame, from: toVC.bigTitle.superview) 217 | 218 | albumLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 219 | albumLabel.frame = containerView.convert(toVC.albumLbl.frame, from: toVC.albumLbl.superview) 220 | albumLabel.textAlignment = .center 221 | 222 | yearLabel.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 223 | yearLabel.frame = containerView.convert(toVC.yearLbl.frame, from: toVC.yearLbl.superview) 224 | yearLabel.textAlignment = .center 225 | 226 | 227 | imageViewSnapshotCancel.frame = containerView.convert(toVC.cancelImageView.frame, from: toVC.cancelImageView.superview) 228 | imageViewSnapshotPlay.frame = containerView.convert(toVC.playImageView.frame, from: toVC.playImageView.superview) 229 | imageViewSnapshotLike.frame = containerView.convert(toVC.likeImageView.frame, from: toVC.likeImageView.superview) 230 | 231 | imageViewSnapshotBackground.frame = containerView.convert(toVC.backgroundImageView.frame, from: toVC.backgroundImageView.superview) 232 | 233 | 234 | cellBackground.layoutIfNeeded() 235 | 236 | } 237 | }() 238 | 239 | 240 | 241 | animator1.addCompletion { _ in 242 | animator2.startAnimation() 243 | 244 | // Group Animator 245 | doBezierAnimation(showLayerAnimation: false) 246 | 247 | } 248 | 249 | 250 | animator2.addCompletion { _ in 251 | 252 | // Background 253 | cellBackground.removeFromSuperview() 254 | 255 | // Labels 256 | titleLabel.removeFromSuperview() 257 | albumLabel.removeFromSuperview() 258 | yearLabel.removeFromSuperview() 259 | 260 | // TOP 261 | imageViewSnapshotProfile.removeFromSuperview() 262 | imageViewSnapshotPlus.removeFromSuperview() 263 | imageViewSnapshotBackground.removeFromSuperview() 264 | 265 | // BOTTOM 266 | imageViewSnapshotCancel.removeFromSuperview() 267 | imageViewSnapshotPlay.removeFromSuperview() 268 | imageViewSnapshotLike.removeFromSuperview() 269 | 270 | fromViewController.view.removeFromSuperview() 271 | 272 | toViewController.view.isHidden = false 273 | 274 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 275 | 276 | 277 | } 278 | 279 | 280 | 281 | animator1.startAnimation() 282 | 283 | 284 | 285 | func doBezierAnimation(showLayerAnimation: Bool = false) { 286 | 287 | 288 | //*** PROFILE IMAGE ***// 289 | 290 | // Profile Animation 291 | var bezierPath = UIBezierPath() 292 | bezierPath.move(to: CGPoint(x: imageViewSnapshotProfile.frame.midX, y: imageViewSnapshotProfile.frame.midY)) 293 | bezierPath.addQuadCurve(to: CGPoint(x: UIScreen.main.bounds.width / 2 , y: frameProfile.midY), controlPoint: CGPoint(x: frameProfile.midX/2, y: frameProfile.midY/2)) 294 | 295 | 296 | var shapeLayer = CAShapeLayer() 297 | // The Bezier path that we made needs to be converted to a CGPath before it can be used on a layer. 298 | shapeLayer.path = bezierPath.cgPath 299 | shapeLayer.strokeColor = UIColor.blue.cgColor 300 | shapeLayer.fillColor = UIColor.clear.cgColor 301 | shapeLayer.lineWidth = 1.0 302 | 303 | // Enable/Disable for debug 304 | if showLayerAnimation { 305 | containerView.layer.addSublayer(shapeLayer) 306 | } 307 | 308 | let profileAnimationPosition = CAKeyframeAnimation(keyPath: "position") 309 | profileAnimationPosition.path = bezierPath.cgPath 310 | // I set this one to make the animation go smoothly along the path 311 | profileAnimationPosition.calculationMode = kCAAnimationPaced 312 | profileAnimationPosition.duration = 0.3 313 | profileAnimationPosition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 314 | 315 | 316 | let profileAnimationBounds = CAKeyframeAnimation(keyPath: "bounds") 317 | profileAnimationBounds.duration = 0.3 318 | profileAnimationBounds.values = [imageViewSnapshotProfile.frame, containerView.convert(toVC.profileImageView.frame, from: toVC.profileImageView.superview)] 319 | profileAnimationBounds.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 320 | profileAnimationBounds.beginTime = 0 321 | 322 | // Let's group the animation for position and bounds into one 323 | let groupProfile = CAAnimationGroup() 324 | groupProfile.animations = [profileAnimationPosition, profileAnimationBounds] 325 | groupProfile.duration = 0.3 326 | groupProfile.repeatCount = 0 327 | groupProfile.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 328 | groupProfile.isRemovedOnCompletion = false 329 | groupProfile.fillMode = kCAFillModeForwards 330 | 331 | imageViewSnapshotProfile.layer.add(groupProfile, forKey: "profileAnimation") 332 | 333 | 334 | //*** PLUS IMAGE ***// 335 | 336 | // Plus ImageView Animation 337 | bezierPath = UIBezierPath() 338 | bezierPath.move(to: CGPoint(x: imageViewSnapshotPlus.frame.maxX, y: imageViewSnapshotPlus.frame.maxY)) 339 | bezierPath.addQuadCurve(to: CGPoint(x: (UIScreen.main.bounds.width / 2) + 20, y: framePlus.maxY - 10), controlPoint: CGPoint(x:framePlus.maxX + 30, y: framePlus.maxY/4)) 340 | 341 | 342 | shapeLayer = CAShapeLayer() 343 | 344 | // The Bezier path that we made needs to be converted to 345 | shapeLayer.path = bezierPath.cgPath 346 | shapeLayer.strokeColor = UIColor.blue.cgColor 347 | shapeLayer.fillColor = UIColor.clear.cgColor 348 | shapeLayer.lineWidth = 1.0 349 | 350 | // Enable/Disable for debug 351 | if showLayerAnimation { 352 | containerView.layer.addSublayer(shapeLayer) 353 | } 354 | 355 | 356 | 357 | let plusAnimationPosition = CAKeyframeAnimation(keyPath: "position") 358 | plusAnimationPosition.path = bezierPath.cgPath 359 | // I set this one to make the animation go smoothly along the path 360 | plusAnimationPosition.calculationMode = kCAAnimationPaced 361 | plusAnimationPosition.duration = 0.3 362 | plusAnimationPosition.rotationMode = kCAAnimationLinear 363 | plusAnimationPosition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 364 | 365 | 366 | let plusAnimationBounds = CAKeyframeAnimation(keyPath: "bounds") 367 | plusAnimationBounds.duration = 0.3 368 | plusAnimationBounds.values = [imageViewSnapshotPlus.frame, containerView.convert(toVC.plusImageView.frame, from: toVC.plusImageView.superview)] 369 | plusAnimationBounds.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 370 | plusAnimationBounds.beginTime = 0 371 | 372 | // Let's group the animation for position and bounds into one 373 | let groupPlus = CAAnimationGroup() 374 | groupPlus.animations = [plusAnimationPosition, plusAnimationBounds] 375 | groupPlus.duration = 0.3 376 | groupPlus.repeatCount = 0 377 | groupPlus.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 378 | groupPlus.isRemovedOnCompletion = false 379 | groupPlus.fillMode = kCAFillModeForwards 380 | 381 | imageViewSnapshotPlus.layer.add(groupPlus, forKey: "doit") 382 | 383 | 384 | } 385 | 386 | } 387 | 388 | 389 | 390 | } 391 | 392 | 393 | -------------------------------------------------------------------------------- /AnimationExampleAdvanced.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 81BCA8C021510B1000CA0E66 /* MainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81BCA8BE21510B1000CA0E66 /* MainTableViewCell.swift */; }; 11 | 81BCA8C121510B1000CA0E66 /* MainTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 81BCA8BF21510B1000CA0E66 /* MainTableViewCell.xib */; }; 12 | A10ACF5A22F4BF28001640A0 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = A10ACF5922F4BF28001640A0 /* README.md */; }; 13 | A10ACF6622F4C6B4001640A0 /* TransitionCordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10ACF6522F4C6B4001640A0 /* TransitionCordinator.swift */; }; 14 | A10ACF6822F4DBCF001640A0 /* MainViewController+DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10ACF6722F4DBCF001640A0 /* MainViewController+DataSource.swift */; }; 15 | A10ACF6A22F4DC14001640A0 /* MainViewController+ProtocolTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A10ACF6922F4DC14001640A0 /* MainViewController+ProtocolTransition.swift */; }; 16 | A19C21A021471E8600CDC6ED /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C219F21471E8600CDC6ED /* AppDelegate.swift */; }; 17 | A19C21A221471E8600CDC6ED /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21A121471E8600CDC6ED /* ViewController.swift */; }; 18 | A19C21A521471E8600CDC6ED /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A19C21A321471E8600CDC6ED /* Main.storyboard */; }; 19 | A19C21A721471E9100CDC6ED /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A19C21A621471E9100CDC6ED /* Assets.xcassets */; }; 20 | A19C21AA21471E9100CDC6ED /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A19C21A821471E9100CDC6ED /* LaunchScreen.storyboard */; }; 21 | A19C21B921471FCB00CDC6ED /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A19C21B121471FCB00CDC6ED /* MainViewController.xib */; }; 22 | A19C21BC21471FCB00CDC6ED /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21B521471FCB00CDC6ED /* MainViewController.swift */; }; 23 | A19C21C321474D5800CDC6ED /* PushedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21C121474D5800CDC6ED /* PushedViewController.swift */; }; 24 | A19C21C421474D5800CDC6ED /* PushedViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A19C21C221474D5800CDC6ED /* PushedViewController.xib */; }; 25 | A19C21C621474F6400CDC6ED /* PopAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21C521474F6400CDC6ED /* PopAnimator.swift */; }; 26 | A19C21C82149F14F00CDC6ED /* PushAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21C72149F14F00CDC6ED /* PushAnimator.swift */; }; 27 | A19C21CA2149F16200CDC6ED /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A19C21C92149F16200CDC6ED /* Helpers.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 81BCA8BE21510B1000CA0E66 /* MainTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTableViewCell.swift; sourceTree = ""; }; 32 | 81BCA8BF21510B1000CA0E66 /* MainTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainTableViewCell.xib; sourceTree = ""; }; 33 | A10ACF5922F4BF28001640A0 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 34 | A10ACF6522F4C6B4001640A0 /* TransitionCordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionCordinator.swift; sourceTree = ""; }; 35 | A10ACF6722F4DBCF001640A0 /* MainViewController+DataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainViewController+DataSource.swift"; sourceTree = ""; }; 36 | A10ACF6922F4DC14001640A0 /* MainViewController+ProtocolTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainViewController+ProtocolTransition.swift"; sourceTree = ""; }; 37 | A19C219C21471E8600CDC6ED /* AnimationExampleAdvanced.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AnimationExampleAdvanced.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | A19C219F21471E8600CDC6ED /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | A19C21A121471E8600CDC6ED /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 40 | A19C21A421471E8600CDC6ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 41 | A19C21A621471E9100CDC6ED /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 42 | A19C21A921471E9100CDC6ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 43 | A19C21AB21471E9100CDC6ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | A19C21B121471FCB00CDC6ED /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; 45 | A19C21B521471FCB00CDC6ED /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 46 | A19C21C121474D5800CDC6ED /* PushedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushedViewController.swift; sourceTree = ""; }; 47 | A19C21C221474D5800CDC6ED /* PushedViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PushedViewController.xib; sourceTree = ""; }; 48 | A19C21C521474F6400CDC6ED /* PopAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopAnimator.swift; sourceTree = ""; }; 49 | A19C21C72149F14F00CDC6ED /* PushAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAnimator.swift; sourceTree = ""; }; 50 | A19C21C92149F16200CDC6ED /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | A19C219921471E8600CDC6ED /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | A10ACF5B22F4BF30001640A0 /* Models */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | ); 68 | path = Models; 69 | sourceTree = ""; 70 | }; 71 | A10ACF5C22F4BF3F001640A0 /* ViewModels */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | ); 75 | path = ViewModels; 76 | sourceTree = ""; 77 | }; 78 | A10ACF5D22F4BF46001640A0 /* Views */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | A10ACF5E22F4BF4C001640A0 /* Cells */, 82 | ); 83 | path = Views; 84 | sourceTree = ""; 85 | }; 86 | A10ACF5E22F4BF4C001640A0 /* Cells */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 81BCA8BF21510B1000CA0E66 /* MainTableViewCell.xib */, 90 | 81BCA8BE21510B1000CA0E66 /* MainTableViewCell.swift */, 91 | ); 92 | path = Cells; 93 | sourceTree = ""; 94 | }; 95 | A10ACF5F22F4BF53001640A0 /* Controllers */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | A19C21B521471FCB00CDC6ED /* MainViewController.swift */, 99 | A10ACF6722F4DBCF001640A0 /* MainViewController+DataSource.swift */, 100 | A10ACF6922F4DC14001640A0 /* MainViewController+ProtocolTransition.swift */, 101 | A19C21B121471FCB00CDC6ED /* MainViewController.xib */, 102 | A19C21C121474D5800CDC6ED /* PushedViewController.swift */, 103 | A19C21C221474D5800CDC6ED /* PushedViewController.xib */, 104 | ); 105 | path = Controllers; 106 | sourceTree = ""; 107 | }; 108 | A10ACF6022F4BF66001640A0 /* Helpers */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | A19C21C92149F16200CDC6ED /* Helpers.swift */, 112 | ); 113 | path = Helpers; 114 | sourceTree = ""; 115 | }; 116 | A10ACF6122F4BF72001640A0 /* Common */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | A10ACF6222F4BF78001640A0 /* ViewControllerTransitions */, 120 | A10ACF6322F4C418001640A0 /* Navigation */, 121 | ); 122 | path = Common; 123 | sourceTree = ""; 124 | }; 125 | A10ACF6222F4BF78001640A0 /* ViewControllerTransitions */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | A19C21C72149F14F00CDC6ED /* PushAnimator.swift */, 129 | A19C21C521474F6400CDC6ED /* PopAnimator.swift */, 130 | ); 131 | path = ViewControllerTransitions; 132 | sourceTree = ""; 133 | }; 134 | A10ACF6322F4C418001640A0 /* Navigation */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | A10ACF6522F4C6B4001640A0 /* TransitionCordinator.swift */, 138 | ); 139 | path = Navigation; 140 | sourceTree = ""; 141 | }; 142 | A19C219321471E8600CDC6ED = { 143 | isa = PBXGroup; 144 | children = ( 145 | A19C219E21471E8600CDC6ED /* AnimationExampleAdvanced */, 146 | A19C219D21471E8600CDC6ED /* Products */, 147 | ); 148 | sourceTree = ""; 149 | }; 150 | A19C219D21471E8600CDC6ED /* Products */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | A19C219C21471E8600CDC6ED /* AnimationExampleAdvanced.app */, 154 | ); 155 | name = Products; 156 | sourceTree = ""; 157 | }; 158 | A19C219E21471E8600CDC6ED /* AnimationExampleAdvanced */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | A10ACF5922F4BF28001640A0 /* README.md */, 162 | A10ACF5B22F4BF30001640A0 /* Models */, 163 | A10ACF5C22F4BF3F001640A0 /* ViewModels */, 164 | A10ACF5D22F4BF46001640A0 /* Views */, 165 | A10ACF5F22F4BF53001640A0 /* Controllers */, 166 | A10ACF6022F4BF66001640A0 /* Helpers */, 167 | A10ACF6122F4BF72001640A0 /* Common */, 168 | A19C219F21471E8600CDC6ED /* AppDelegate.swift */, 169 | A19C21A121471E8600CDC6ED /* ViewController.swift */, 170 | A19C21A321471E8600CDC6ED /* Main.storyboard */, 171 | A19C21A621471E9100CDC6ED /* Assets.xcassets */, 172 | A19C21A821471E9100CDC6ED /* LaunchScreen.storyboard */, 173 | A19C21AB21471E9100CDC6ED /* Info.plist */, 174 | ); 175 | path = AnimationExampleAdvanced; 176 | sourceTree = ""; 177 | }; 178 | /* End PBXGroup section */ 179 | 180 | /* Begin PBXNativeTarget section */ 181 | A19C219B21471E8600CDC6ED /* AnimationExampleAdvanced */ = { 182 | isa = PBXNativeTarget; 183 | buildConfigurationList = A19C21AE21471E9100CDC6ED /* Build configuration list for PBXNativeTarget "AnimationExampleAdvanced" */; 184 | buildPhases = ( 185 | A19C219821471E8600CDC6ED /* Sources */, 186 | A19C219921471E8600CDC6ED /* Frameworks */, 187 | A19C219A21471E8600CDC6ED /* Resources */, 188 | ); 189 | buildRules = ( 190 | ); 191 | dependencies = ( 192 | ); 193 | name = AnimationExampleAdvanced; 194 | productName = AnimationExample; 195 | productReference = A19C219C21471E8600CDC6ED /* AnimationExampleAdvanced.app */; 196 | productType = "com.apple.product-type.application"; 197 | }; 198 | /* End PBXNativeTarget section */ 199 | 200 | /* Begin PBXProject section */ 201 | A19C219421471E8600CDC6ED /* Project object */ = { 202 | isa = PBXProject; 203 | attributes = { 204 | LastSwiftUpdateCheck = 0930; 205 | LastUpgradeCheck = 0930; 206 | ORGANIZATIONNAME = "Francisco Obarrio"; 207 | TargetAttributes = { 208 | A19C219B21471E8600CDC6ED = { 209 | CreatedOnToolsVersion = 9.3; 210 | }; 211 | }; 212 | }; 213 | buildConfigurationList = A19C219721471E8600CDC6ED /* Build configuration list for PBXProject "AnimationExampleAdvanced" */; 214 | compatibilityVersion = "Xcode 9.3"; 215 | developmentRegion = en; 216 | hasScannedForEncodings = 0; 217 | knownRegions = ( 218 | en, 219 | Base, 220 | ); 221 | mainGroup = A19C219321471E8600CDC6ED; 222 | productRefGroup = A19C219D21471E8600CDC6ED /* Products */; 223 | projectDirPath = ""; 224 | projectRoot = ""; 225 | targets = ( 226 | A19C219B21471E8600CDC6ED /* AnimationExampleAdvanced */, 227 | ); 228 | }; 229 | /* End PBXProject section */ 230 | 231 | /* Begin PBXResourcesBuildPhase section */ 232 | A19C219A21471E8600CDC6ED /* Resources */ = { 233 | isa = PBXResourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | A19C21AA21471E9100CDC6ED /* LaunchScreen.storyboard in Resources */, 237 | A19C21A721471E9100CDC6ED /* Assets.xcassets in Resources */, 238 | A19C21B921471FCB00CDC6ED /* MainViewController.xib in Resources */, 239 | A10ACF5A22F4BF28001640A0 /* README.md in Resources */, 240 | 81BCA8C121510B1000CA0E66 /* MainTableViewCell.xib in Resources */, 241 | A19C21A521471E8600CDC6ED /* Main.storyboard in Resources */, 242 | A19C21C421474D5800CDC6ED /* PushedViewController.xib in Resources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXResourcesBuildPhase section */ 247 | 248 | /* Begin PBXSourcesBuildPhase section */ 249 | A19C219821471E8600CDC6ED /* Sources */ = { 250 | isa = PBXSourcesBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | A19C21BC21471FCB00CDC6ED /* MainViewController.swift in Sources */, 254 | A19C21C621474F6400CDC6ED /* PopAnimator.swift in Sources */, 255 | A10ACF6A22F4DC14001640A0 /* MainViewController+ProtocolTransition.swift in Sources */, 256 | A19C21CA2149F16200CDC6ED /* Helpers.swift in Sources */, 257 | A10ACF6622F4C6B4001640A0 /* TransitionCordinator.swift in Sources */, 258 | 81BCA8C021510B1000CA0E66 /* MainTableViewCell.swift in Sources */, 259 | A19C21A221471E8600CDC6ED /* ViewController.swift in Sources */, 260 | A19C21C321474D5800CDC6ED /* PushedViewController.swift in Sources */, 261 | A19C21C82149F14F00CDC6ED /* PushAnimator.swift in Sources */, 262 | A19C21A021471E8600CDC6ED /* AppDelegate.swift in Sources */, 263 | A10ACF6822F4DBCF001640A0 /* MainViewController+DataSource.swift in Sources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXSourcesBuildPhase section */ 268 | 269 | /* Begin PBXVariantGroup section */ 270 | A19C21A321471E8600CDC6ED /* Main.storyboard */ = { 271 | isa = PBXVariantGroup; 272 | children = ( 273 | A19C21A421471E8600CDC6ED /* Base */, 274 | ); 275 | name = Main.storyboard; 276 | sourceTree = ""; 277 | }; 278 | A19C21A821471E9100CDC6ED /* LaunchScreen.storyboard */ = { 279 | isa = PBXVariantGroup; 280 | children = ( 281 | A19C21A921471E9100CDC6ED /* Base */, 282 | ); 283 | name = LaunchScreen.storyboard; 284 | sourceTree = ""; 285 | }; 286 | /* End PBXVariantGroup section */ 287 | 288 | /* Begin XCBuildConfiguration section */ 289 | A19C21AC21471E9100CDC6ED /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ALWAYS_SEARCH_USER_PATHS = NO; 293 | CLANG_ANALYZER_NONNULL = YES; 294 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 295 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 296 | CLANG_CXX_LIBRARY = "libc++"; 297 | CLANG_ENABLE_MODULES = YES; 298 | CLANG_ENABLE_OBJC_ARC = YES; 299 | CLANG_ENABLE_OBJC_WEAK = YES; 300 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_COMMA = YES; 303 | CLANG_WARN_CONSTANT_CONVERSION = YES; 304 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 305 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 306 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 307 | CLANG_WARN_EMPTY_BODY = YES; 308 | CLANG_WARN_ENUM_CONVERSION = YES; 309 | CLANG_WARN_INFINITE_RECURSION = YES; 310 | CLANG_WARN_INT_CONVERSION = YES; 311 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 312 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 313 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 314 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 315 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 316 | CLANG_WARN_STRICT_PROTOTYPES = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 318 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 319 | CLANG_WARN_UNREACHABLE_CODE = YES; 320 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 321 | CODE_SIGN_IDENTITY = "iPhone Developer"; 322 | COPY_PHASE_STRIP = NO; 323 | DEBUG_INFORMATION_FORMAT = dwarf; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | ENABLE_TESTABILITY = YES; 326 | GCC_C_LANGUAGE_STANDARD = gnu11; 327 | GCC_DYNAMIC_NO_PIC = NO; 328 | GCC_NO_COMMON_BLOCKS = YES; 329 | GCC_OPTIMIZATION_LEVEL = 0; 330 | GCC_PREPROCESSOR_DEFINITIONS = ( 331 | "DEBUG=1", 332 | "$(inherited)", 333 | ); 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 341 | MTL_ENABLE_DEBUG_INFO = YES; 342 | ONLY_ACTIVE_ARCH = YES; 343 | SDKROOT = iphoneos; 344 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 345 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 346 | }; 347 | name = Debug; 348 | }; 349 | A19C21AD21471E9100CDC6ED /* Release */ = { 350 | isa = XCBuildConfiguration; 351 | buildSettings = { 352 | ALWAYS_SEARCH_USER_PATHS = NO; 353 | CLANG_ANALYZER_NONNULL = YES; 354 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 355 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 356 | CLANG_CXX_LIBRARY = "libc++"; 357 | CLANG_ENABLE_MODULES = YES; 358 | CLANG_ENABLE_OBJC_ARC = YES; 359 | CLANG_ENABLE_OBJC_WEAK = YES; 360 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 361 | CLANG_WARN_BOOL_CONVERSION = YES; 362 | CLANG_WARN_COMMA = YES; 363 | CLANG_WARN_CONSTANT_CONVERSION = YES; 364 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 365 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 366 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 367 | CLANG_WARN_EMPTY_BODY = YES; 368 | CLANG_WARN_ENUM_CONVERSION = YES; 369 | CLANG_WARN_INFINITE_RECURSION = YES; 370 | CLANG_WARN_INT_CONVERSION = YES; 371 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 372 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 373 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 374 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 375 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 376 | CLANG_WARN_STRICT_PROTOTYPES = YES; 377 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 378 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 379 | CLANG_WARN_UNREACHABLE_CODE = YES; 380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 381 | CODE_SIGN_IDENTITY = "iPhone Developer"; 382 | COPY_PHASE_STRIP = NO; 383 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 384 | ENABLE_NS_ASSERTIONS = NO; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu11; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 390 | GCC_WARN_UNDECLARED_SELECTOR = YES; 391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 392 | GCC_WARN_UNUSED_FUNCTION = YES; 393 | GCC_WARN_UNUSED_VARIABLE = YES; 394 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 395 | MTL_ENABLE_DEBUG_INFO = NO; 396 | SDKROOT = iphoneos; 397 | SWIFT_COMPILATION_MODE = wholemodule; 398 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 399 | VALIDATE_PRODUCT = YES; 400 | }; 401 | name = Release; 402 | }; 403 | A19C21AF21471E9100CDC6ED /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 407 | CODE_SIGN_IDENTITY = "iPhone Developer"; 408 | CODE_SIGN_STYLE = Automatic; 409 | DEVELOPMENT_TEAM = E8FV83GSJC; 410 | INFOPLIST_FILE = AnimationExampleAdvanced/Info.plist; 411 | LD_RUNPATH_SEARCH_PATHS = ( 412 | "$(inherited)", 413 | "@executable_path/Frameworks", 414 | ); 415 | PRODUCT_BUNDLE_IDENTIFIER = com.franobarrio.AnimationAdvanced; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | PROVISIONING_PROFILE = ""; 418 | PROVISIONING_PROFILE_SPECIFIER = ""; 419 | SWIFT_VERSION = 4.0; 420 | TARGETED_DEVICE_FAMILY = "1,2"; 421 | }; 422 | name = Debug; 423 | }; 424 | A19C21B021471E9100CDC6ED /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 428 | CODE_SIGN_IDENTITY = "iPhone Developer"; 429 | CODE_SIGN_STYLE = Automatic; 430 | DEVELOPMENT_TEAM = E8FV83GSJC; 431 | INFOPLIST_FILE = AnimationExampleAdvanced/Info.plist; 432 | LD_RUNPATH_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "@executable_path/Frameworks", 435 | ); 436 | PRODUCT_BUNDLE_IDENTIFIER = com.franobarrio.AnimationAdvanced; 437 | PRODUCT_NAME = "$(TARGET_NAME)"; 438 | PROVISIONING_PROFILE_SPECIFIER = ""; 439 | SWIFT_VERSION = 4.0; 440 | TARGETED_DEVICE_FAMILY = "1,2"; 441 | }; 442 | name = Release; 443 | }; 444 | /* End XCBuildConfiguration section */ 445 | 446 | /* Begin XCConfigurationList section */ 447 | A19C219721471E8600CDC6ED /* Build configuration list for PBXProject "AnimationExampleAdvanced" */ = { 448 | isa = XCConfigurationList; 449 | buildConfigurations = ( 450 | A19C21AC21471E9100CDC6ED /* Debug */, 451 | A19C21AD21471E9100CDC6ED /* Release */, 452 | ); 453 | defaultConfigurationIsVisible = 0; 454 | defaultConfigurationName = Release; 455 | }; 456 | A19C21AE21471E9100CDC6ED /* Build configuration list for PBXNativeTarget "AnimationExampleAdvanced" */ = { 457 | isa = XCConfigurationList; 458 | buildConfigurations = ( 459 | A19C21AF21471E9100CDC6ED /* Debug */, 460 | A19C21B021471E9100CDC6ED /* Release */, 461 | ); 462 | defaultConfigurationIsVisible = 0; 463 | defaultConfigurationName = Release; 464 | }; 465 | /* End XCConfigurationList section */ 466 | }; 467 | rootObject = A19C219421471E8600CDC6ED /* Project object */; 468 | } 469 | --------------------------------------------------------------------------------