├── .gitignore ├── CustomModalTransition.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── CustomModalTransition ├── AppDelegate.h ├── AppDelegate.m ├── CustomModalTransition-Info.plist ├── CustomModalTransition-Prefix.pch ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── ModalNavigationController.h ├── ModalNavigationController.m ├── ModalTransitionAnimator.h ├── ModalTransitionAnimator.m ├── ModalTransitionDelegate.h ├── ModalTransitionDelegate.m ├── ModalViewController.h ├── ModalViewController.m ├── RootNavigationController.h ├── RootNavigationController.m ├── RootViewController.h ├── RootViewController.m ├── en.lproj │ └── InfoPlist.strings └── main.m ├── CustomModalTransitionTests ├── CustomModalTransitionTests-Info.plist ├── CustomModalTransitionTests.m └── en.lproj │ └── InfoPlist.strings ├── README.md ├── ScreenRecording.gif └── Storyboard.storyboard /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ -------------------------------------------------------------------------------- /CustomModalTransition.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 584F66401A9623FB0027DA3B /* ModalTransitionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 584F663F1A9623FB0027DA3B /* ModalTransitionDelegate.m */; }; 11 | 584FA0821937BBE600B81627 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA0811937BBE600B81627 /* Foundation.framework */; }; 12 | 584FA0841937BBE600B81627 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA0831937BBE600B81627 /* CoreGraphics.framework */; }; 13 | 584FA0861937BBE600B81627 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA0851937BBE600B81627 /* UIKit.framework */; }; 14 | 584FA08C1937BBE600B81627 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 584FA08A1937BBE600B81627 /* InfoPlist.strings */; }; 15 | 584FA08E1937BBE600B81627 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA08D1937BBE600B81627 /* main.m */; }; 16 | 584FA0921937BBE600B81627 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0911937BBE600B81627 /* AppDelegate.m */; }; 17 | 584FA0941937BBE600B81627 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 584FA0931937BBE600B81627 /* Images.xcassets */; }; 18 | 584FA09B1937BBE600B81627 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA09A1937BBE600B81627 /* XCTest.framework */; }; 19 | 584FA09C1937BBE600B81627 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA0811937BBE600B81627 /* Foundation.framework */; }; 20 | 584FA09D1937BBE600B81627 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 584FA0851937BBE600B81627 /* UIKit.framework */; }; 21 | 584FA0A51937BBE700B81627 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 584FA0A31937BBE700B81627 /* InfoPlist.strings */; }; 22 | 584FA0A71937BBE700B81627 /* CustomModalTransitionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0A61937BBE700B81627 /* CustomModalTransitionTests.m */; }; 23 | 584FA0B11937BC0000B81627 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 584FA0B01937BC0000B81627 /* Storyboard.storyboard */; }; 24 | 584FA0B41937BCD600B81627 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0B31937BCD600B81627 /* RootViewController.m */; }; 25 | 584FA0B71937BCFE00B81627 /* ModalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0B61937BCFE00B81627 /* ModalViewController.m */; }; 26 | 584FA0BA1937BDEF00B81627 /* RootNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0B91937BDEF00B81627 /* RootNavigationController.m */; }; 27 | 584FA0BD1937BE0900B81627 /* ModalNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0BC1937BE0900B81627 /* ModalNavigationController.m */; }; 28 | 584FA0C01937BEE900B81627 /* ModalTransitionAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 584FA0BF1937BEE900B81627 /* ModalTransitionAnimator.m */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 584FA09E1937BBE700B81627 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 584FA0761937BBE600B81627 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 584FA07D1937BBE600B81627; 37 | remoteInfo = CustomModalTransition; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 584F663E1A9623FB0027DA3B /* ModalTransitionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalTransitionDelegate.h; sourceTree = ""; }; 43 | 584F663F1A9623FB0027DA3B /* ModalTransitionDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalTransitionDelegate.m; sourceTree = ""; }; 44 | 584FA07E1937BBE600B81627 /* CustomModalTransition.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomModalTransition.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 584FA0811937BBE600B81627 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | 584FA0831937BBE600B81627 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | 584FA0851937BBE600B81627 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | 584FA0891937BBE600B81627 /* CustomModalTransition-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CustomModalTransition-Info.plist"; sourceTree = ""; }; 49 | 584FA08B1937BBE600B81627 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | 584FA08D1937BBE600B81627 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 584FA08F1937BBE600B81627 /* CustomModalTransition-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CustomModalTransition-Prefix.pch"; sourceTree = ""; }; 52 | 584FA0901937BBE600B81627 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 53 | 584FA0911937BBE600B81627 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 54 | 584FA0931937BBE600B81627 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 55 | 584FA0991937BBE600B81627 /* CustomModalTransitionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomModalTransitionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 584FA09A1937BBE600B81627 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 57 | 584FA0A21937BBE700B81627 /* CustomModalTransitionTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CustomModalTransitionTests-Info.plist"; sourceTree = ""; }; 58 | 584FA0A41937BBE700B81627 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 59 | 584FA0A61937BBE700B81627 /* CustomModalTransitionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomModalTransitionTests.m; sourceTree = ""; }; 60 | 584FA0B01937BC0000B81627 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Storyboard.storyboard; path = ../Storyboard.storyboard; sourceTree = ""; }; 61 | 584FA0B21937BCD600B81627 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; 62 | 584FA0B31937BCD600B81627 /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; 63 | 584FA0B51937BCFE00B81627 /* ModalViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalViewController.h; sourceTree = ""; }; 64 | 584FA0B61937BCFE00B81627 /* ModalViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalViewController.m; sourceTree = ""; }; 65 | 584FA0B81937BDEF00B81627 /* RootNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootNavigationController.h; sourceTree = ""; }; 66 | 584FA0B91937BDEF00B81627 /* RootNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootNavigationController.m; sourceTree = ""; }; 67 | 584FA0BB1937BE0900B81627 /* ModalNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalNavigationController.h; sourceTree = ""; }; 68 | 584FA0BC1937BE0900B81627 /* ModalNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalNavigationController.m; sourceTree = ""; }; 69 | 584FA0BE1937BEE900B81627 /* ModalTransitionAnimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalTransitionAnimator.h; sourceTree = ""; }; 70 | 584FA0BF1937BEE900B81627 /* ModalTransitionAnimator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalTransitionAnimator.m; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 584FA07B1937BBE600B81627 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 584FA0841937BBE600B81627 /* CoreGraphics.framework in Frameworks */, 79 | 584FA0861937BBE600B81627 /* UIKit.framework in Frameworks */, 80 | 584FA0821937BBE600B81627 /* Foundation.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 584FA0961937BBE600B81627 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | 584FA09B1937BBE600B81627 /* XCTest.framework in Frameworks */, 89 | 584FA09D1937BBE600B81627 /* UIKit.framework in Frameworks */, 90 | 584FA09C1937BBE600B81627 /* Foundation.framework in Frameworks */, 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXFrameworksBuildPhase section */ 95 | 96 | /* Begin PBXGroup section */ 97 | 584F66411A9624020027DA3B /* Modal transition classes */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 584FA0BE1937BEE900B81627 /* ModalTransitionAnimator.h */, 101 | 584FA0BF1937BEE900B81627 /* ModalTransitionAnimator.m */, 102 | 584F663E1A9623FB0027DA3B /* ModalTransitionDelegate.h */, 103 | 584F663F1A9623FB0027DA3B /* ModalTransitionDelegate.m */, 104 | ); 105 | name = "Modal transition classes"; 106 | sourceTree = ""; 107 | }; 108 | 584FA0751937BBE600B81627 = { 109 | isa = PBXGroup; 110 | children = ( 111 | 584FA0871937BBE600B81627 /* CustomModalTransition */, 112 | 584FA0A01937BBE700B81627 /* CustomModalTransitionTests */, 113 | 584FA0801937BBE600B81627 /* Frameworks */, 114 | 584FA07F1937BBE600B81627 /* Products */, 115 | ); 116 | sourceTree = ""; 117 | }; 118 | 584FA07F1937BBE600B81627 /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 584FA07E1937BBE600B81627 /* CustomModalTransition.app */, 122 | 584FA0991937BBE600B81627 /* CustomModalTransitionTests.xctest */, 123 | ); 124 | name = Products; 125 | sourceTree = ""; 126 | }; 127 | 584FA0801937BBE600B81627 /* Frameworks */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 584FA0811937BBE600B81627 /* Foundation.framework */, 131 | 584FA0831937BBE600B81627 /* CoreGraphics.framework */, 132 | 584FA0851937BBE600B81627 /* UIKit.framework */, 133 | 584FA09A1937BBE600B81627 /* XCTest.framework */, 134 | ); 135 | name = Frameworks; 136 | sourceTree = ""; 137 | }; 138 | 584FA0871937BBE600B81627 /* CustomModalTransition */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 584F66411A9624020027DA3B /* Modal transition classes */, 142 | 584FA0901937BBE600B81627 /* AppDelegate.h */, 143 | 584FA0911937BBE600B81627 /* AppDelegate.m */, 144 | 584FA0B21937BCD600B81627 /* RootViewController.h */, 145 | 584FA0B31937BCD600B81627 /* RootViewController.m */, 146 | 584FA0B81937BDEF00B81627 /* RootNavigationController.h */, 147 | 584FA0B91937BDEF00B81627 /* RootNavigationController.m */, 148 | 584FA0B51937BCFE00B81627 /* ModalViewController.h */, 149 | 584FA0B61937BCFE00B81627 /* ModalViewController.m */, 150 | 584FA0BB1937BE0900B81627 /* ModalNavigationController.h */, 151 | 584FA0BC1937BE0900B81627 /* ModalNavigationController.m */, 152 | 584FA0B01937BC0000B81627 /* Storyboard.storyboard */, 153 | 584FA0931937BBE600B81627 /* Images.xcassets */, 154 | 584FA0881937BBE600B81627 /* Supporting Files */, 155 | ); 156 | path = CustomModalTransition; 157 | sourceTree = ""; 158 | }; 159 | 584FA0881937BBE600B81627 /* Supporting Files */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 584FA0891937BBE600B81627 /* CustomModalTransition-Info.plist */, 163 | 584FA08A1937BBE600B81627 /* InfoPlist.strings */, 164 | 584FA08D1937BBE600B81627 /* main.m */, 165 | 584FA08F1937BBE600B81627 /* CustomModalTransition-Prefix.pch */, 166 | ); 167 | name = "Supporting Files"; 168 | sourceTree = ""; 169 | }; 170 | 584FA0A01937BBE700B81627 /* CustomModalTransitionTests */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 584FA0A61937BBE700B81627 /* CustomModalTransitionTests.m */, 174 | 584FA0A11937BBE700B81627 /* Supporting Files */, 175 | ); 176 | path = CustomModalTransitionTests; 177 | sourceTree = ""; 178 | }; 179 | 584FA0A11937BBE700B81627 /* Supporting Files */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 584FA0A21937BBE700B81627 /* CustomModalTransitionTests-Info.plist */, 183 | 584FA0A31937BBE700B81627 /* InfoPlist.strings */, 184 | ); 185 | name = "Supporting Files"; 186 | sourceTree = ""; 187 | }; 188 | /* End PBXGroup section */ 189 | 190 | /* Begin PBXNativeTarget section */ 191 | 584FA07D1937BBE600B81627 /* CustomModalTransition */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 584FA0AA1937BBE700B81627 /* Build configuration list for PBXNativeTarget "CustomModalTransition" */; 194 | buildPhases = ( 195 | 584FA07A1937BBE600B81627 /* Sources */, 196 | 584FA07B1937BBE600B81627 /* Frameworks */, 197 | 584FA07C1937BBE600B81627 /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | ); 203 | name = CustomModalTransition; 204 | productName = CustomModalTransition; 205 | productReference = 584FA07E1937BBE600B81627 /* CustomModalTransition.app */; 206 | productType = "com.apple.product-type.application"; 207 | }; 208 | 584FA0981937BBE600B81627 /* CustomModalTransitionTests */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 584FA0AD1937BBE700B81627 /* Build configuration list for PBXNativeTarget "CustomModalTransitionTests" */; 211 | buildPhases = ( 212 | 584FA0951937BBE600B81627 /* Sources */, 213 | 584FA0961937BBE600B81627 /* Frameworks */, 214 | 584FA0971937BBE600B81627 /* Resources */, 215 | ); 216 | buildRules = ( 217 | ); 218 | dependencies = ( 219 | 584FA09F1937BBE700B81627 /* PBXTargetDependency */, 220 | ); 221 | name = CustomModalTransitionTests; 222 | productName = CustomModalTransitionTests; 223 | productReference = 584FA0991937BBE600B81627 /* CustomModalTransitionTests.xctest */; 224 | productType = "com.apple.product-type.bundle.unit-test"; 225 | }; 226 | /* End PBXNativeTarget section */ 227 | 228 | /* Begin PBXProject section */ 229 | 584FA0761937BBE600B81627 /* Project object */ = { 230 | isa = PBXProject; 231 | attributes = { 232 | LastUpgradeCheck = 0510; 233 | ORGANIZATIONNAME = codeispoetry.ru; 234 | TargetAttributes = { 235 | 584FA0981937BBE600B81627 = { 236 | TestTargetID = 584FA07D1937BBE600B81627; 237 | }; 238 | }; 239 | }; 240 | buildConfigurationList = 584FA0791937BBE600B81627 /* Build configuration list for PBXProject "CustomModalTransition" */; 241 | compatibilityVersion = "Xcode 3.2"; 242 | developmentRegion = English; 243 | hasScannedForEncodings = 0; 244 | knownRegions = ( 245 | en, 246 | ); 247 | mainGroup = 584FA0751937BBE600B81627; 248 | productRefGroup = 584FA07F1937BBE600B81627 /* Products */; 249 | projectDirPath = ""; 250 | projectRoot = ""; 251 | targets = ( 252 | 584FA07D1937BBE600B81627 /* CustomModalTransition */, 253 | 584FA0981937BBE600B81627 /* CustomModalTransitionTests */, 254 | ); 255 | }; 256 | /* End PBXProject section */ 257 | 258 | /* Begin PBXResourcesBuildPhase section */ 259 | 584FA07C1937BBE600B81627 /* Resources */ = { 260 | isa = PBXResourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | 584FA08C1937BBE600B81627 /* InfoPlist.strings in Resources */, 264 | 584FA0941937BBE600B81627 /* Images.xcassets in Resources */, 265 | 584FA0B11937BC0000B81627 /* Storyboard.storyboard in Resources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | 584FA0971937BBE600B81627 /* Resources */ = { 270 | isa = PBXResourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | 584FA0A51937BBE700B81627 /* InfoPlist.strings in Resources */, 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | /* End PBXResourcesBuildPhase section */ 278 | 279 | /* Begin PBXSourcesBuildPhase section */ 280 | 584FA07A1937BBE600B81627 /* Sources */ = { 281 | isa = PBXSourcesBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | 584FA0B71937BCFE00B81627 /* ModalViewController.m in Sources */, 285 | 584FA0BD1937BE0900B81627 /* ModalNavigationController.m in Sources */, 286 | 584FA0C01937BEE900B81627 /* ModalTransitionAnimator.m in Sources */, 287 | 584FA0921937BBE600B81627 /* AppDelegate.m in Sources */, 288 | 584FA08E1937BBE600B81627 /* main.m in Sources */, 289 | 584FA0BA1937BDEF00B81627 /* RootNavigationController.m in Sources */, 290 | 584FA0B41937BCD600B81627 /* RootViewController.m in Sources */, 291 | 584F66401A9623FB0027DA3B /* ModalTransitionDelegate.m in Sources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 584FA0951937BBE600B81627 /* Sources */ = { 296 | isa = PBXSourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 584FA0A71937BBE700B81627 /* CustomModalTransitionTests.m in Sources */, 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | /* End PBXSourcesBuildPhase section */ 304 | 305 | /* Begin PBXTargetDependency section */ 306 | 584FA09F1937BBE700B81627 /* PBXTargetDependency */ = { 307 | isa = PBXTargetDependency; 308 | target = 584FA07D1937BBE600B81627 /* CustomModalTransition */; 309 | targetProxy = 584FA09E1937BBE700B81627 /* PBXContainerItemProxy */; 310 | }; 311 | /* End PBXTargetDependency section */ 312 | 313 | /* Begin PBXVariantGroup section */ 314 | 584FA08A1937BBE600B81627 /* InfoPlist.strings */ = { 315 | isa = PBXVariantGroup; 316 | children = ( 317 | 584FA08B1937BBE600B81627 /* en */, 318 | ); 319 | name = InfoPlist.strings; 320 | sourceTree = ""; 321 | }; 322 | 584FA0A31937BBE700B81627 /* InfoPlist.strings */ = { 323 | isa = PBXVariantGroup; 324 | children = ( 325 | 584FA0A41937BBE700B81627 /* en */, 326 | ); 327 | name = InfoPlist.strings; 328 | sourceTree = ""; 329 | }; 330 | /* End PBXVariantGroup section */ 331 | 332 | /* Begin XCBuildConfiguration section */ 333 | 584FA0A81937BBE700B81627 /* Debug */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | ALWAYS_SEARCH_USER_PATHS = NO; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BOOL_CONVERSION = YES; 342 | CLANG_WARN_CONSTANT_CONVERSION = YES; 343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 344 | CLANG_WARN_EMPTY_BODY = YES; 345 | CLANG_WARN_ENUM_CONVERSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 348 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 350 | COPY_PHASE_STRIP = NO; 351 | GCC_C_LANGUAGE_STANDARD = gnu99; 352 | GCC_DYNAMIC_NO_PIC = NO; 353 | GCC_OPTIMIZATION_LEVEL = 0; 354 | GCC_PREPROCESSOR_DEFINITIONS = ( 355 | "DEBUG=1", 356 | "$(inherited)", 357 | ); 358 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 361 | GCC_WARN_UNDECLARED_SELECTOR = YES; 362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 363 | GCC_WARN_UNUSED_FUNCTION = YES; 364 | GCC_WARN_UNUSED_VARIABLE = YES; 365 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 366 | ONLY_ACTIVE_ARCH = YES; 367 | SDKROOT = iphoneos; 368 | }; 369 | name = Debug; 370 | }; 371 | 584FA0A91937BBE700B81627 /* Release */ = { 372 | isa = XCBuildConfiguration; 373 | buildSettings = { 374 | ALWAYS_SEARCH_USER_PATHS = NO; 375 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 376 | CLANG_CXX_LIBRARY = "libc++"; 377 | CLANG_ENABLE_MODULES = YES; 378 | CLANG_ENABLE_OBJC_ARC = YES; 379 | CLANG_WARN_BOOL_CONVERSION = YES; 380 | CLANG_WARN_CONSTANT_CONVERSION = YES; 381 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 382 | CLANG_WARN_EMPTY_BODY = YES; 383 | CLANG_WARN_ENUM_CONVERSION = YES; 384 | CLANG_WARN_INT_CONVERSION = YES; 385 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 386 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 387 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 388 | COPY_PHASE_STRIP = YES; 389 | ENABLE_NS_ASSERTIONS = NO; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 392 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 393 | GCC_WARN_UNDECLARED_SELECTOR = YES; 394 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 395 | GCC_WARN_UNUSED_FUNCTION = YES; 396 | GCC_WARN_UNUSED_VARIABLE = YES; 397 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 398 | SDKROOT = iphoneos; 399 | VALIDATE_PRODUCT = YES; 400 | }; 401 | name = Release; 402 | }; 403 | 584FA0AB1937BBE700B81627 /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 407 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 408 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 409 | GCC_PREFIX_HEADER = "CustomModalTransition/CustomModalTransition-Prefix.pch"; 410 | INFOPLIST_FILE = "CustomModalTransition/CustomModalTransition-Info.plist"; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | TARGETED_DEVICE_FAMILY = 1; 413 | WRAPPER_EXTENSION = app; 414 | }; 415 | name = Debug; 416 | }; 417 | 584FA0AC1937BBE700B81627 /* Release */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 421 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 422 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 423 | GCC_PREFIX_HEADER = "CustomModalTransition/CustomModalTransition-Prefix.pch"; 424 | INFOPLIST_FILE = "CustomModalTransition/CustomModalTransition-Info.plist"; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | TARGETED_DEVICE_FAMILY = 1; 427 | WRAPPER_EXTENSION = app; 428 | }; 429 | name = Release; 430 | }; 431 | 584FA0AE1937BBE700B81627 /* Debug */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CustomModalTransition.app/CustomModalTransition"; 435 | FRAMEWORK_SEARCH_PATHS = ( 436 | "$(SDKROOT)/Developer/Library/Frameworks", 437 | "$(inherited)", 438 | "$(DEVELOPER_FRAMEWORKS_DIR)", 439 | ); 440 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 441 | GCC_PREFIX_HEADER = "CustomModalTransition/CustomModalTransition-Prefix.pch"; 442 | GCC_PREPROCESSOR_DEFINITIONS = ( 443 | "DEBUG=1", 444 | "$(inherited)", 445 | ); 446 | INFOPLIST_FILE = "CustomModalTransitionTests/CustomModalTransitionTests-Info.plist"; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | TEST_HOST = "$(BUNDLE_LOADER)"; 449 | WRAPPER_EXTENSION = xctest; 450 | }; 451 | name = Debug; 452 | }; 453 | 584FA0AF1937BBE700B81627 /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/CustomModalTransition.app/CustomModalTransition"; 457 | FRAMEWORK_SEARCH_PATHS = ( 458 | "$(SDKROOT)/Developer/Library/Frameworks", 459 | "$(inherited)", 460 | "$(DEVELOPER_FRAMEWORKS_DIR)", 461 | ); 462 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 463 | GCC_PREFIX_HEADER = "CustomModalTransition/CustomModalTransition-Prefix.pch"; 464 | INFOPLIST_FILE = "CustomModalTransitionTests/CustomModalTransitionTests-Info.plist"; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | TEST_HOST = "$(BUNDLE_LOADER)"; 467 | WRAPPER_EXTENSION = xctest; 468 | }; 469 | name = Release; 470 | }; 471 | /* End XCBuildConfiguration section */ 472 | 473 | /* Begin XCConfigurationList section */ 474 | 584FA0791937BBE600B81627 /* Build configuration list for PBXProject "CustomModalTransition" */ = { 475 | isa = XCConfigurationList; 476 | buildConfigurations = ( 477 | 584FA0A81937BBE700B81627 /* Debug */, 478 | 584FA0A91937BBE700B81627 /* Release */, 479 | ); 480 | defaultConfigurationIsVisible = 0; 481 | defaultConfigurationName = Release; 482 | }; 483 | 584FA0AA1937BBE700B81627 /* Build configuration list for PBXNativeTarget "CustomModalTransition" */ = { 484 | isa = XCConfigurationList; 485 | buildConfigurations = ( 486 | 584FA0AB1937BBE700B81627 /* Debug */, 487 | 584FA0AC1937BBE700B81627 /* Release */, 488 | ); 489 | defaultConfigurationIsVisible = 0; 490 | defaultConfigurationName = Release; 491 | }; 492 | 584FA0AD1937BBE700B81627 /* Build configuration list for PBXNativeTarget "CustomModalTransitionTests" */ = { 493 | isa = XCConfigurationList; 494 | buildConfigurations = ( 495 | 584FA0AE1937BBE700B81627 /* Debug */, 496 | 584FA0AF1937BBE700B81627 /* Release */, 497 | ); 498 | defaultConfigurationIsVisible = 0; 499 | defaultConfigurationName = Release; 500 | }; 501 | /* End XCConfigurationList section */ 502 | }; 503 | rootObject = 584FA0761937BBE600B81627 /* Project object */; 504 | } 505 | -------------------------------------------------------------------------------- /CustomModalTransition.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CustomModalTransition/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CustomModalTransition/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 14 | return YES; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CustomModalTransition/CustomModalTransition-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | ru.codeispoetry.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Storyboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationPortraitUpsideDown 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationLandscapeRight 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CustomModalTransition/CustomModalTransition-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /CustomModalTransition/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /CustomModalTransition/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /CustomModalTransition/ModalNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalNavigationController.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ModalNavigationController : UINavigationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalNavigationController.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "ModalNavigationController.h" 10 | 11 | @implementation ModalNavigationController 12 | 13 | // Forward status bar appearance to child view controller 14 | - (UIViewController*)childViewControllerForStatusBarStyle { 15 | return self.topViewController; 16 | } 17 | 18 | - (UIViewController*)childViewControllerForStatusBarHidden { 19 | return self.topViewController; 20 | } 21 | 22 | - (void)viewDidAppear:(BOOL)animated { 23 | [super viewDidAppear:animated]; 24 | 25 | NSLog(@"%s", __PRETTY_FUNCTION__); 26 | } 27 | 28 | - (void)viewWillAppear:(BOOL)animated { 29 | [super viewWillAppear:animated]; 30 | 31 | NSLog(@"%s", __PRETTY_FUNCTION__); 32 | } 33 | 34 | - (void)viewDidDisappear:(BOOL)animated { 35 | [super viewDidDisappear:animated]; 36 | 37 | NSLog(@"%s", __PRETTY_FUNCTION__); 38 | } 39 | 40 | - (void)viewWillDisappear:(BOOL)animated { 41 | [super viewWillDisappear:animated]; 42 | 43 | NSLog(@"%s", __PRETTY_FUNCTION__); 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalTransitionAnimator.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionAnimator.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ModalTransitionAnimator : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalTransitionAnimator.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionAnimator.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "ModalTransitionAnimator.h" 10 | 11 | @implementation ModalTransitionAnimator 12 | 13 | - (NSTimeInterval)transitionDuration:(id)transitionContext { 14 | return 0.6; 15 | } 16 | 17 | - (void)animateTransition:(id)transitionContext { 18 | UIViewController* destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 19 | 20 | if([destination isBeingPresented]) { 21 | [self animatePresentation:transitionContext]; 22 | } else { 23 | [self animateDismissal:transitionContext]; 24 | } 25 | } 26 | 27 | // 28 | // Calculate a final frame for presenting controller according to interface orientation 29 | // Presenting controller should always slide down and its top should coincide with the bottom of screen 30 | // 31 | - (CGRect)presentingControllerFrameWithContext:(id)transitionContext { 32 | CGRect frame = transitionContext.containerView.bounds; 33 | 34 | if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) // iOS 8+ 35 | { 36 | // 37 | // On iOS 8, UIKit handles rotation using transform matrix 38 | // Therefore we should always return a frame for portrait mode 39 | // 40 | return CGRectMake(0, CGRectGetHeight(frame), CGRectGetWidth(frame), CGRectGetHeight(frame)); 41 | } 42 | else 43 | { 44 | // 45 | // On iOS 7, UIKit does not handle rotation 46 | // To make sure our view is moving in the right direction (always down) we should 47 | // fix the frame accoding to interface orientation. 48 | // 49 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 50 | 51 | switch (orientation) { 52 | case UIInterfaceOrientationLandscapeLeft: 53 | return CGRectMake(CGRectGetWidth(frame), 0, CGRectGetWidth(frame), CGRectGetHeight(frame)); 54 | break; 55 | case UIInterfaceOrientationLandscapeRight: 56 | return CGRectMake(-CGRectGetWidth(frame), 0, CGRectGetWidth(frame), CGRectGetHeight(frame)); 57 | break; 58 | case UIInterfaceOrientationPortraitUpsideDown: 59 | return CGRectMake(0, -CGRectGetHeight(frame), CGRectGetWidth(frame), CGRectGetHeight(frame)); 60 | break; 61 | default: 62 | case UIInterfaceOrientationPortrait: 63 | return CGRectMake(0, CGRectGetHeight(frame), CGRectGetWidth(frame), CGRectGetHeight(frame)); 64 | break; 65 | } 66 | } 67 | } 68 | 69 | - (void)animatePresentation:(id)transitionContext 70 | { 71 | NSTimeInterval transitionDuration = [self transitionDuration:transitionContext]; 72 | UIViewController* source = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 73 | UIViewController* destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 74 | UIView* container = transitionContext.containerView; 75 | 76 | // Orientation bug fix 77 | // See: http://stackoverflow.com/a/20061872/351305 78 | destination.view.frame = container.bounds; 79 | source.view.frame = container.bounds; 80 | 81 | // Place container view before source view 82 | [container.superview sendSubviewToBack:container]; 83 | 84 | // Add destination view to container 85 | [container addSubview:destination.view]; 86 | 87 | // Move destination snapshot back in Z plane 88 | // Important: original transform3d is different from CATransform3DIdentity 89 | CATransform3D originalTransform = destination.view.layer.transform; 90 | 91 | // Apply custom transform 92 | CATransform3D perspectiveTransform = originalTransform; 93 | perspectiveTransform.m34 = 1.0 / -1000.0; 94 | perspectiveTransform = CATransform3DTranslate(perspectiveTransform, 0, 0, -100); 95 | destination.view.layer.transform = perspectiveTransform; 96 | 97 | // Start appearance transition for source controller 98 | // Because UIKit does not do this automatically 99 | [source beginAppearanceTransition:NO animated:YES]; 100 | 101 | // Animate 102 | [UIView animateKeyframesWithDuration:transitionDuration delay:0.0 103 | options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{ 104 | [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1.0 animations:^{ 105 | source.view.frame = [self presentingControllerFrameWithContext:transitionContext]; 106 | }]; 107 | [UIView addKeyframeWithRelativeStartTime:0.2 relativeDuration:0.8 animations:^{ 108 | destination.view.layer.transform = originalTransform; 109 | }]; 110 | } completion:^(BOOL finished) { 111 | // End appearance transition for source controller 112 | [source endAppearanceTransition]; 113 | 114 | // Finish transition 115 | [transitionContext completeTransition:YES]; 116 | }]; 117 | } 118 | 119 | - (void)animateDismissal:(id)transitionContext 120 | { 121 | NSTimeInterval transitionDuration = [self transitionDuration:transitionContext]; 122 | UIViewController* source = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 123 | UIViewController* destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 124 | UIView* container = transitionContext.containerView; 125 | 126 | // Orientation bug fix 127 | // See: http://stackoverflow.com/a/20061872/351305 128 | destination.view.frame = container.bounds; 129 | source.view.frame = container.bounds; 130 | 131 | // Move destination view below source view 132 | destination.view.frame = [self presentingControllerFrameWithContext:transitionContext]; 133 | 134 | // Start appearance transition for destination controller 135 | // Because UIKit does not do this automatically 136 | [destination beginAppearanceTransition:YES animated:YES]; 137 | 138 | // Animate 139 | [UIView animateKeyframesWithDuration:transitionDuration delay:0.0 140 | options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{ 141 | [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1.0 animations:^{ 142 | destination.view.frame = container.bounds; 143 | }]; 144 | [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:1.0 animations:^{ 145 | // Important: original transform3d is different from CATransform3DIdentity 146 | CATransform3D perspectiveTransform = source.view.layer.transform; 147 | 148 | perspectiveTransform.m34 = 1.0 / -1000.0; 149 | perspectiveTransform = CATransform3DTranslate(perspectiveTransform, 0, 0, -100); 150 | source.view.layer.transform = perspectiveTransform; 151 | }]; 152 | } completion:^(BOOL finished) { 153 | // End appearance transition for destination controller 154 | [destination endAppearanceTransition]; 155 | 156 | // Finish transition 157 | [transitionContext completeTransition:YES]; 158 | }]; 159 | } 160 | 161 | @end 162 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalTransitionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionDelegate.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 2/19/15. 6 | // Copyright (c) 2015 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ModalTransitionDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalTransitionDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalTransitionDelegate.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 2/19/15. 6 | // Copyright (c) 2015 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "ModalTransitionDelegate.h" 10 | #import "ModalTransitionAnimator.h" 11 | 12 | @implementation ModalTransitionDelegate 13 | 14 | - (id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 15 | return [ModalTransitionAnimator new]; 16 | } 17 | 18 | - (id )animationControllerForDismissedController:(UIViewController *)dismissed { 19 | return [ModalTransitionAnimator new]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ModalViewController.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ModalViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/ModalViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ModalViewController.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "ModalViewController.h" 10 | 11 | @implementation ModalViewController 12 | 13 | - (UIStatusBarStyle)preferredStatusBarStyle { 14 | return UIStatusBarStyleLightContent; 15 | } 16 | 17 | - (void)viewDidAppear:(BOOL)animated { 18 | [super viewDidAppear:animated]; 19 | 20 | NSLog(@"%s", __PRETTY_FUNCTION__); 21 | } 22 | 23 | - (void)viewWillAppear:(BOOL)animated { 24 | [super viewWillAppear:animated]; 25 | 26 | NSLog(@"%s", __PRETTY_FUNCTION__); 27 | } 28 | 29 | - (void)viewDidDisappear:(BOOL)animated { 30 | [super viewDidDisappear:animated]; 31 | 32 | NSLog(@"%s", __PRETTY_FUNCTION__); 33 | } 34 | 35 | - (void)viewWillDisappear:(BOOL)animated { 36 | [super viewWillDisappear:animated]; 37 | 38 | NSLog(@"%s", __PRETTY_FUNCTION__); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CustomModalTransition/RootNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootNavigationController.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RootNavigationController : UINavigationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/RootNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootNavigationController.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "RootNavigationController.h" 10 | 11 | @implementation RootNavigationController 12 | 13 | // Forward status bar appearance to child view controller 14 | - (UIViewController*)childViewControllerForStatusBarStyle { 15 | return self.topViewController; 16 | } 17 | 18 | - (UIViewController*)childViewControllerForStatusBarHidden { 19 | return self.topViewController; 20 | } 21 | 22 | - (void)viewDidAppear:(BOOL)animated { 23 | [super viewDidAppear:animated]; 24 | 25 | NSLog(@"%s", __PRETTY_FUNCTION__); 26 | } 27 | 28 | - (void)viewWillAppear:(BOOL)animated { 29 | [super viewWillAppear:animated]; 30 | 31 | NSLog(@"%s", __PRETTY_FUNCTION__); 32 | } 33 | 34 | - (void)viewDidDisappear:(BOOL)animated { 35 | [super viewDidDisappear:animated]; 36 | 37 | NSLog(@"%s", __PRETTY_FUNCTION__); 38 | } 39 | 40 | - (void)viewWillDisappear:(BOOL)animated { 41 | [super viewWillDisappear:animated]; 42 | 43 | NSLog(@"%s", __PRETTY_FUNCTION__); 44 | } 45 | 46 | - (UIStoryboardSegue*)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier { 47 | // UIKit bug: http://stackoverflow.com/a/28607309/351305 48 | return [toViewController segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CustomModalTransition/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RootViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalTransition/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "ModalTransitionDelegate.h" 11 | 12 | @interface RootViewController() 13 | 14 | @property (nonatomic) ModalTransitionDelegate* transitionDelegate; 15 | 16 | @end 17 | 18 | @implementation RootViewController 19 | 20 | - (ModalTransitionDelegate*)transitionDelegate { 21 | if(!_transitionDelegate) { 22 | _transitionDelegate = [ModalTransitionDelegate new]; 23 | } 24 | return _transitionDelegate; 25 | } 26 | 27 | - (UIStatusBarStyle)preferredStatusBarStyle { 28 | return UIStatusBarStyleDefault; 29 | } 30 | 31 | - (void)viewDidAppear:(BOOL)animated { 32 | [super viewDidAppear:animated]; 33 | 34 | NSLog(@"%s", __PRETTY_FUNCTION__); 35 | } 36 | 37 | - (void)viewWillAppear:(BOOL)animated { 38 | [super viewWillAppear:animated]; 39 | 40 | NSLog(@"%s", __PRETTY_FUNCTION__); 41 | } 42 | 43 | - (void)viewDidDisappear:(BOOL)animated { 44 | [super viewDidDisappear:animated]; 45 | 46 | NSLog(@"%s", __PRETTY_FUNCTION__); 47 | } 48 | 49 | - (void)viewWillDisappear:(BOOL)animated { 50 | [super viewWillDisappear:animated]; 51 | 52 | NSLog(@"%s", __PRETTY_FUNCTION__); 53 | } 54 | 55 | #pragma mark - Segues 56 | 57 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 58 | UIViewController* controller = (UIViewController*)segue.destinationViewController; 59 | 60 | controller.transitioningDelegate = self.transitionDelegate; 61 | controller.modalPresentationStyle = UIModalPresentationCustom; 62 | controller.modalPresentationCapturesStatusBarAppearance = YES; 63 | } 64 | 65 | - (IBAction)unwindToRootViewController:(UIStoryboardSegue*)unwindSegue {} 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /CustomModalTransition/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CustomModalTransition/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CustomModalTransition 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CustomModalTransitionTests/CustomModalTransitionTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ru.codeispoetry.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CustomModalTransitionTests/CustomModalTransitionTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomModalTransitionTests.m 3 | // CustomModalTransitionTests 4 | // 5 | // Created by pronebird on 29/05/14. 6 | // Copyright (c) 2014 codeispoetry.ru. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CustomModalTransitionTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation CustomModalTransitionTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CustomModalTransitionTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Custom modal transition 2 | ===================== 3 | 4 | 5 | 6 | A custom transition I developed for one of my apps. It works on iOS 7 - iOS 8.2. 7 | 8 | ### UIPresentationController update (iOS 8 only) 9 | 10 | A solution using `UIPresentationController` and without iOS 7 hacks can be found in [ios8 branch](https://github.com/pronebird/CustomModalTransition/tree/ios8). It features properly handled appearance events, device orientations support and much less code. 11 | 12 | ### Caveats 13 | 14 | - Controllers will not properly rotate if orientation changed when presented. There is only one exception, if presented controller is a navigation controller, then rotation works fine. This seems to be a UIKit bug on iOS 7 or iOS 8. `UIPresentationController` solves that problem by providing a way to resize controllers on orientation change. 15 | - State restoration is possible but presented VC should restore `transitioningDelegate`, `modalPresentationStyle` and `modalPresentationCapturesStatusBarAppearance`. If you use storyboards then it's easy: 16 | 17 | ```objc 18 | - (void)encodeRestorableStateWithCoder:(NSCoder *)coder { 19 | [super encodeRestorableStateWithCoder:coder]; 20 | 21 | [coder encodeInteger:self.modalPresentationStyle forKey:@"modalPresentationStyle"]; 22 | [coder encodeInteger:self.modalPresentationCapturesStatusBarAppearance forKey:@"modalPresentationCapturesStatusBarAppearance"]; 23 | [coder encodeObject:self.transitioningDelegate forKey:@"transitioningDelegate"]; 24 | } 25 | 26 | - (void)decodeRestorableStateWithCoder:(NSCoder *)coder { 27 | [super decodeRestorableStateWithCoder:coder]; 28 | 29 | self.modalPresentationStyle = [coder decodeIntegerForKey:@"modalPresentationStyle"]; 30 | self.modalPresentationCapturesStatusBarAppearance = [coder decodeIntegerForKey:@"modalPresentationCapturesStatusBarAppearance"]; 31 | self.transitioningDelegate = [coder decodeObjectForKey:@"transitioningDelegate"]; 32 | } 33 | ``` 34 | 35 | ### Blog post 36 | 37 | This project is a part of [my blog post](https://coderwall.com/p/njtb0q). However lots of things changed since original blog post was published. 38 | 39 | - Unwinding works fine if you fix `segueForUnwindingToViewController` in source navigation controller and create unwind segue using source view controller. Works for both iOS 7 and 8 (see http://stackoverflow.com/a/28607309/351305) 40 | - Resetting views' frames to container bounds before adding them to container helps to solve issues with misplaced navigation bar and rotation issues on iOS 7. 41 | -------------------------------------------------------------------------------- /ScreenRecording.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pronebird/CustomModalTransition/d0b9d3f2d402d26e34de8226964b0e6405e68b22/ScreenRecording.gif -------------------------------------------------------------------------------- /Storyboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 45 | 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 | 103 | 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 | --------------------------------------------------------------------------------