├── CustomModalAnimation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── houwan.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── houwan.xcuserdatad │ └── xcschemes │ ├── CustomModalAnimation.xcscheme │ └── xcschememanagement.plist ├── CustomModalAnimation ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── bg1.imageset │ │ ├── Contents.json │ │ └── bg1.jpeg ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Demo1 │ ├── BCustomPresentationController.h │ ├── BCustomPresentationController.m │ ├── BViewController.h │ └── BViewController.m ├── Demo2 │ ├── SecPresentationController.h │ ├── SecPresentationController.m │ ├── SecondViewController.h │ └── SecondViewController.m ├── Demo3 │ ├── Demo3ViewController.h │ └── Demo3ViewController.m ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m ├── README.md └── iOSApp3.gif /CustomModalAnimation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 87E754A71E71423F009D0702 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754A61E71423F009D0702 /* main.m */; }; 11 | 87E754AA1E714240009D0702 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754A91E714240009D0702 /* AppDelegate.m */; }; 12 | 87E754AD1E714240009D0702 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754AC1E714240009D0702 /* ViewController.m */; }; 13 | 87E754B01E714240009D0702 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87E754AE1E714240009D0702 /* Main.storyboard */; }; 14 | 87E754B21E714240009D0702 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87E754B11E714240009D0702 /* Assets.xcassets */; }; 15 | 87E754B51E714240009D0702 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87E754B31E714240009D0702 /* LaunchScreen.storyboard */; }; 16 | 87E754C01E714808009D0702 /* BViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754BF1E714808009D0702 /* BViewController.m */; }; 17 | 87E754C61E714968009D0702 /* BCustomPresentationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754C51E714968009D0702 /* BCustomPresentationController.m */; }; 18 | 87E754C91E715745009D0702 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754C81E715745009D0702 /* SecondViewController.m */; }; 19 | 87E754CC1E7158BF009D0702 /* SecPresentationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754CB1E7158BF009D0702 /* SecPresentationController.m */; }; 20 | 87E754D01E716303009D0702 /* Demo3ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87E754CF1E716303009D0702 /* Demo3ViewController.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 87E754A21E71423F009D0702 /* CustomModalAnimation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomModalAnimation.app; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 87E754A61E71423F009D0702 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 26 | 87E754A81E71423F009D0702 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 27 | 87E754A91E714240009D0702 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 28 | 87E754AB1E714240009D0702 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 29 | 87E754AC1E714240009D0702 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 30 | 87E754AF1E714240009D0702 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 31 | 87E754B11E714240009D0702 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 32 | 87E754B41E714240009D0702 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 33 | 87E754B61E714240009D0702 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | 87E754BE1E714808009D0702 /* BViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BViewController.h; sourceTree = ""; }; 35 | 87E754BF1E714808009D0702 /* BViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BViewController.m; sourceTree = ""; }; 36 | 87E754C41E714968009D0702 /* BCustomPresentationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BCustomPresentationController.h; sourceTree = ""; }; 37 | 87E754C51E714968009D0702 /* BCustomPresentationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BCustomPresentationController.m; sourceTree = ""; }; 38 | 87E754C71E715745009D0702 /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 39 | 87E754C81E715745009D0702 /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 40 | 87E754CA1E7158BF009D0702 /* SecPresentationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPresentationController.h; sourceTree = ""; }; 41 | 87E754CB1E7158BF009D0702 /* SecPresentationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecPresentationController.m; sourceTree = ""; }; 42 | 87E754CE1E716303009D0702 /* Demo3ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Demo3ViewController.h; sourceTree = ""; }; 43 | 87E754CF1E716303009D0702 /* Demo3ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Demo3ViewController.m; sourceTree = ""; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | 87E7549F1E71423F009D0702 /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXFrameworksBuildPhase section */ 55 | 56 | /* Begin PBXGroup section */ 57 | 87E754991E71423E009D0702 = { 58 | isa = PBXGroup; 59 | children = ( 60 | 87E754A41E71423F009D0702 /* CustomModalAnimation */, 61 | 87E754A31E71423F009D0702 /* Products */, 62 | ); 63 | sourceTree = ""; 64 | }; 65 | 87E754A31E71423F009D0702 /* Products */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 87E754A21E71423F009D0702 /* CustomModalAnimation.app */, 69 | ); 70 | name = Products; 71 | sourceTree = ""; 72 | }; 73 | 87E754A41E71423F009D0702 /* CustomModalAnimation */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 87E754BC1E714517009D0702 /* Demo1 */, 77 | 87E754BD1E714517009D0702 /* Demo2 */, 78 | 87E754CD1E716248009D0702 /* Demo3 */, 79 | 87E754A81E71423F009D0702 /* AppDelegate.h */, 80 | 87E754A91E714240009D0702 /* AppDelegate.m */, 81 | 87E754AB1E714240009D0702 /* ViewController.h */, 82 | 87E754AC1E714240009D0702 /* ViewController.m */, 83 | 87E754AE1E714240009D0702 /* Main.storyboard */, 84 | 87E754B11E714240009D0702 /* Assets.xcassets */, 85 | 87E754B31E714240009D0702 /* LaunchScreen.storyboard */, 86 | 87E754B61E714240009D0702 /* Info.plist */, 87 | 87E754A51E71423F009D0702 /* Supporting Files */, 88 | ); 89 | path = CustomModalAnimation; 90 | sourceTree = ""; 91 | }; 92 | 87E754A51E71423F009D0702 /* Supporting Files */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 87E754A61E71423F009D0702 /* main.m */, 96 | ); 97 | name = "Supporting Files"; 98 | sourceTree = ""; 99 | }; 100 | 87E754BC1E714517009D0702 /* Demo1 */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 87E754BE1E714808009D0702 /* BViewController.h */, 104 | 87E754BF1E714808009D0702 /* BViewController.m */, 105 | 87E754C41E714968009D0702 /* BCustomPresentationController.h */, 106 | 87E754C51E714968009D0702 /* BCustomPresentationController.m */, 107 | ); 108 | path = Demo1; 109 | sourceTree = ""; 110 | }; 111 | 87E754BD1E714517009D0702 /* Demo2 */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 87E754C71E715745009D0702 /* SecondViewController.h */, 115 | 87E754C81E715745009D0702 /* SecondViewController.m */, 116 | 87E754CA1E7158BF009D0702 /* SecPresentationController.h */, 117 | 87E754CB1E7158BF009D0702 /* SecPresentationController.m */, 118 | ); 119 | path = Demo2; 120 | sourceTree = ""; 121 | }; 122 | 87E754CD1E716248009D0702 /* Demo3 */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 87E754CE1E716303009D0702 /* Demo3ViewController.h */, 126 | 87E754CF1E716303009D0702 /* Demo3ViewController.m */, 127 | ); 128 | path = Demo3; 129 | sourceTree = ""; 130 | }; 131 | /* End PBXGroup section */ 132 | 133 | /* Begin PBXNativeTarget section */ 134 | 87E754A11E71423F009D0702 /* CustomModalAnimation */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = 87E754B91E714240009D0702 /* Build configuration list for PBXNativeTarget "CustomModalAnimation" */; 137 | buildPhases = ( 138 | 87E7549E1E71423F009D0702 /* Sources */, 139 | 87E7549F1E71423F009D0702 /* Frameworks */, 140 | 87E754A01E71423F009D0702 /* Resources */, 141 | ); 142 | buildRules = ( 143 | ); 144 | dependencies = ( 145 | ); 146 | name = CustomModalAnimation; 147 | productName = CustomModalAnimation; 148 | productReference = 87E754A21E71423F009D0702 /* CustomModalAnimation.app */; 149 | productType = "com.apple.product-type.application"; 150 | }; 151 | /* End PBXNativeTarget section */ 152 | 153 | /* Begin PBXProject section */ 154 | 87E7549A1E71423E009D0702 /* Project object */ = { 155 | isa = PBXProject; 156 | attributes = { 157 | LastUpgradeCheck = 0820; 158 | ORGANIZATIONNAME = HW; 159 | TargetAttributes = { 160 | 87E754A11E71423F009D0702 = { 161 | CreatedOnToolsVersion = 8.2.1; 162 | ProvisioningStyle = Automatic; 163 | }; 164 | }; 165 | }; 166 | buildConfigurationList = 87E7549D1E71423E009D0702 /* Build configuration list for PBXProject "CustomModalAnimation" */; 167 | compatibilityVersion = "Xcode 3.2"; 168 | developmentRegion = English; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | Base, 173 | ); 174 | mainGroup = 87E754991E71423E009D0702; 175 | productRefGroup = 87E754A31E71423F009D0702 /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | 87E754A11E71423F009D0702 /* CustomModalAnimation */, 180 | ); 181 | }; 182 | /* End PBXProject section */ 183 | 184 | /* Begin PBXResourcesBuildPhase section */ 185 | 87E754A01E71423F009D0702 /* Resources */ = { 186 | isa = PBXResourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 87E754B51E714240009D0702 /* LaunchScreen.storyboard in Resources */, 190 | 87E754B21E714240009D0702 /* Assets.xcassets in Resources */, 191 | 87E754B01E714240009D0702 /* Main.storyboard in Resources */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | /* End PBXResourcesBuildPhase section */ 196 | 197 | /* Begin PBXSourcesBuildPhase section */ 198 | 87E7549E1E71423F009D0702 /* Sources */ = { 199 | isa = PBXSourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | 87E754C91E715745009D0702 /* SecondViewController.m in Sources */, 203 | 87E754AD1E714240009D0702 /* ViewController.m in Sources */, 204 | 87E754CC1E7158BF009D0702 /* SecPresentationController.m in Sources */, 205 | 87E754C61E714968009D0702 /* BCustomPresentationController.m in Sources */, 206 | 87E754C01E714808009D0702 /* BViewController.m in Sources */, 207 | 87E754AA1E714240009D0702 /* AppDelegate.m in Sources */, 208 | 87E754A71E71423F009D0702 /* main.m in Sources */, 209 | 87E754D01E716303009D0702 /* Demo3ViewController.m in Sources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXSourcesBuildPhase section */ 214 | 215 | /* Begin PBXVariantGroup section */ 216 | 87E754AE1E714240009D0702 /* Main.storyboard */ = { 217 | isa = PBXVariantGroup; 218 | children = ( 219 | 87E754AF1E714240009D0702 /* Base */, 220 | ); 221 | name = Main.storyboard; 222 | sourceTree = ""; 223 | }; 224 | 87E754B31E714240009D0702 /* LaunchScreen.storyboard */ = { 225 | isa = PBXVariantGroup; 226 | children = ( 227 | 87E754B41E714240009D0702 /* Base */, 228 | ); 229 | name = LaunchScreen.storyboard; 230 | sourceTree = ""; 231 | }; 232 | /* End PBXVariantGroup section */ 233 | 234 | /* Begin XCBuildConfiguration section */ 235 | 87E754B71E714240009D0702 /* Debug */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_ANALYZER_NONNULL = YES; 240 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 241 | CLANG_CXX_LIBRARY = "libc++"; 242 | CLANG_ENABLE_MODULES = YES; 243 | CLANG_ENABLE_OBJC_ARC = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_CONSTANT_CONVERSION = YES; 246 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 247 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN_ENUM_CONVERSION = YES; 250 | CLANG_WARN_INFINITE_RECURSION = YES; 251 | CLANG_WARN_INT_CONVERSION = YES; 252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 253 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 254 | CLANG_WARN_UNREACHABLE_CODE = YES; 255 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 256 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 257 | COPY_PHASE_STRIP = NO; 258 | DEBUG_INFORMATION_FORMAT = dwarf; 259 | ENABLE_STRICT_OBJC_MSGSEND = YES; 260 | ENABLE_TESTABILITY = YES; 261 | GCC_C_LANGUAGE_STANDARD = gnu99; 262 | GCC_DYNAMIC_NO_PIC = NO; 263 | GCC_NO_COMMON_BLOCKS = YES; 264 | GCC_OPTIMIZATION_LEVEL = 0; 265 | GCC_PREPROCESSOR_DEFINITIONS = ( 266 | "DEBUG=1", 267 | "$(inherited)", 268 | ); 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 276 | MTL_ENABLE_DEBUG_INFO = YES; 277 | ONLY_ACTIVE_ARCH = YES; 278 | SDKROOT = iphoneos; 279 | }; 280 | name = Debug; 281 | }; 282 | 87E754B81E714240009D0702 /* Release */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | ALWAYS_SEARCH_USER_PATHS = NO; 286 | CLANG_ANALYZER_NONNULL = YES; 287 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 288 | CLANG_CXX_LIBRARY = "libc++"; 289 | CLANG_ENABLE_MODULES = YES; 290 | CLANG_ENABLE_OBJC_ARC = YES; 291 | CLANG_WARN_BOOL_CONVERSION = YES; 292 | CLANG_WARN_CONSTANT_CONVERSION = YES; 293 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 294 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 295 | CLANG_WARN_EMPTY_BODY = YES; 296 | CLANG_WARN_ENUM_CONVERSION = YES; 297 | CLANG_WARN_INFINITE_RECURSION = YES; 298 | CLANG_WARN_INT_CONVERSION = YES; 299 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 300 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 301 | CLANG_WARN_UNREACHABLE_CODE = YES; 302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 304 | COPY_PHASE_STRIP = NO; 305 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 306 | ENABLE_NS_ASSERTIONS = NO; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu99; 309 | GCC_NO_COMMON_BLOCKS = YES; 310 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 311 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 312 | GCC_WARN_UNDECLARED_SELECTOR = YES; 313 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 314 | GCC_WARN_UNUSED_FUNCTION = YES; 315 | GCC_WARN_UNUSED_VARIABLE = YES; 316 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 317 | MTL_ENABLE_DEBUG_INFO = NO; 318 | SDKROOT = iphoneos; 319 | VALIDATE_PRODUCT = YES; 320 | }; 321 | name = Release; 322 | }; 323 | 87E754BA1E714240009D0702 /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 327 | INFOPLIST_FILE = CustomModalAnimation/Info.plist; 328 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 329 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 330 | PRODUCT_BUNDLE_IDENTIFIER = cn.sunpig.WxTsd.CustomModalAnimation; 331 | PRODUCT_NAME = "$(TARGET_NAME)"; 332 | }; 333 | name = Debug; 334 | }; 335 | 87E754BB1E714240009D0702 /* Release */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 339 | INFOPLIST_FILE = CustomModalAnimation/Info.plist; 340 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 341 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 342 | PRODUCT_BUNDLE_IDENTIFIER = cn.sunpig.WxTsd.CustomModalAnimation; 343 | PRODUCT_NAME = "$(TARGET_NAME)"; 344 | }; 345 | name = Release; 346 | }; 347 | /* End XCBuildConfiguration section */ 348 | 349 | /* Begin XCConfigurationList section */ 350 | 87E7549D1E71423E009D0702 /* Build configuration list for PBXProject "CustomModalAnimation" */ = { 351 | isa = XCConfigurationList; 352 | buildConfigurations = ( 353 | 87E754B71E714240009D0702 /* Debug */, 354 | 87E754B81E714240009D0702 /* Release */, 355 | ); 356 | defaultConfigurationIsVisible = 0; 357 | defaultConfigurationName = Release; 358 | }; 359 | 87E754B91E714240009D0702 /* Build configuration list for PBXNativeTarget "CustomModalAnimation" */ = { 360 | isa = XCConfigurationList; 361 | buildConfigurations = ( 362 | 87E754BA1E714240009D0702 /* Debug */, 363 | 87E754BB1E714240009D0702 /* Release */, 364 | ); 365 | defaultConfigurationIsVisible = 0; 366 | }; 367 | /* End XCConfigurationList section */ 368 | }; 369 | rootObject = 87E7549A1E71423E009D0702 /* Project object */; 370 | } 371 | -------------------------------------------------------------------------------- /CustomModalAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CustomModalAnimation.xcodeproj/project.xcworkspace/xcuserdata/houwan.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/CustomModalAnimation/561d9a4b568b9d696b5071ae8b510a224ccc2206/CustomModalAnimation.xcodeproj/project.xcworkspace/xcuserdata/houwan.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CustomModalAnimation.xcodeproj/xcuserdata/houwan.xcuserdatad/xcschemes/CustomModalAnimation.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 | -------------------------------------------------------------------------------- /CustomModalAnimation.xcodeproj/xcuserdata/houwan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CustomModalAnimation.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 87E754A11E71423F009D0702 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CustomModalAnimation/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /CustomModalAnimation/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // 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. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CustomModalAnimation/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /CustomModalAnimation/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /CustomModalAnimation/Assets.xcassets/bg1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "bg1.jpeg", 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 | } -------------------------------------------------------------------------------- /CustomModalAnimation/Assets.xcassets/bg1.imageset/bg1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/CustomModalAnimation/561d9a4b568b9d696b5071ae8b510a224ccc2206/CustomModalAnimation/Assets.xcassets/bg1.imageset/bg1.jpeg -------------------------------------------------------------------------------- /CustomModalAnimation/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CustomModalAnimation/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 39 | 51 | 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 | 121 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 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 | // NOTE: The third view controller is presented with a modalPresentationStyle 174 | of UIModalPresentationOverFullScreen, rather than the default 175 | UIModalPresentationFullScreen (configured in the storyboard). 176 | // 177 | When a fullscreen view controller is presented (the corresponding 178 | presentation controller's -shouldRemovePresentersView returns YES), 179 | the presentation controller temporarily relocates the 180 | presenting view controller's view to the presentation controller's 181 | containerView. When the fullscreen view controller is dismissed, 182 | the presentation controller places the presenting view controller's 183 | view back in its previous superview. 184 | // 185 | The relocation of the presenting view controller's view poses a 186 | problem in this example because only the presenting view controller's 187 | view is relocated, not the intermediate view hierarchy we setup 188 | to apply the rounded corner and shadow effect. If you modify the 189 | modalPresentationStyle of Third View Controller in the storyboard, 190 | you may notice that during the presentation and dismissal animation 191 | for Third View Controller, the rounded corner and shadow effect is 192 | lost. 193 | // 194 | The workaround is to use the UIModalPresentationOverFullScreen 195 | presentation style. This presentation style is similar to 196 | UIModalPresentationFullScreen but the presentation controller for 197 | this presentation style overrides -shouldRemovePresentersView to 198 | return NO, avoiding the above problem. 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo1/BCustomPresentationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HWCustomPresentationController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BCustomPresentationController : UIPresentationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo1/BCustomPresentationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HWCustomPresentationController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "BCustomPresentationController.h" 10 | 11 | @interface BCustomPresentationController () 12 | /** 黑色半透明背景 */ 13 | @property (nonatomic, strong) UIView *dimmingView; 14 | @end 15 | 16 | 17 | 18 | @implementation BCustomPresentationController 19 | 20 | //| ------------------------------第一步内容---------------------------------------------- 21 | #pragma mark - UIViewControllerTransitioningDelegate 22 | /* 23 | * 来告诉控制器,谁是动画主管(UIPresentationController),因为此类继承了UIPresentationController,就返回了self 24 | */ 25 | - (UIPresentationController* )presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source 26 | { 27 | return self; 28 | } 29 | 30 | // 以下两个方法,我们这个Demo,不去实现,即:使用系统默认的 Presented 动画效果,就是从下而上的效果。 31 | // 由于我们没有指定具体动画的效果类,所以第三步也就不用去实现。 32 | 33 | // 返回的对象控制Presented时的动画 (开始动画的具体细节负责类) 34 | //- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 35 | //{ 36 | // return nil; 37 | //} 38 | // 由返回的控制器控制dismissed时的动画 (结束动画的具体细节负责类) 39 | //- (id)animationControllerForDismissedController:(UIViewController *)dismissed 40 | //{ 41 | // return nil; 42 | //} 43 | 44 | 45 | //| ------------------------------第二步内容---------------------------------------------- 46 | #pragma mark - 重写UIPresentationController个别方法 47 | - (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController 48 | { 49 | self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]; 50 | 51 | if (self) { 52 | // 必须设置 presentedViewController 的 modalPresentationStyle 53 | // 在自定义动画效果的情况下,苹果强烈建议设置为 UIModalPresentationCustom 54 | presentedViewController.modalPresentationStyle = UIModalPresentationCustom; 55 | } 56 | 57 | return self; 58 | } 59 | 60 | 61 | // 呈现过渡即将开始的时候被调用的 62 | // 可以在此方法创建和设置自定义动画所需的view 63 | - (void)presentationTransitionWillBegin 64 | { 65 | // 背景遮罩 66 | UIView *dimmingView = [[UIView alloc] initWithFrame:self.containerView.bounds]; 67 | dimmingView.backgroundColor = [UIColor blackColor]; 68 | dimmingView.opaque = NO; //是否透明 69 | dimmingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 70 | [dimmingView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dimmingViewTapped:)]]; 71 | self.dimmingView = dimmingView; 72 | 73 | [self.containerView addSubview:dimmingView]; // 添加到动画容器View中。 74 | 75 | // 获取presentingViewController 的转换协调器,应该动画期间的一个类?上下文?之类的,负责动画的一个东西 76 | id transitionCoordinator = self.presentingViewController.transitionCoordinator; 77 | 78 | // 动画期间,背景View的动画方式 79 | self.dimmingView.alpha = 0.f; 80 | [transitionCoordinator animateAlongsideTransition:^(id context) { 81 | self.dimmingView.alpha = 0.4f; 82 | } completion:NULL]; 83 | } 84 | 85 | #pragma mark 点击了背景遮罩view 86 | - (void)dimmingViewTapped:(UITapGestureRecognizer*)sender 87 | { 88 | [self.presentingViewController dismissViewControllerAnimated:YES completion:NULL]; 89 | } 90 | 91 | // 在呈现过渡结束时被调用的,并且该方法提供一个布尔变量来判断过渡效果是否完成 92 | - (void)presentationTransitionDidEnd:(BOOL)completed 93 | { 94 | // 在取消动画的情况下,可能为NO,这种情况下,应该取消视图的引用,防止视图没有释放 95 | if (!completed) 96 | { 97 | self.dimmingView = nil; 98 | } 99 | } 100 | 101 | // 消失过渡即将开始的时候被调用的 102 | - (void)dismissalTransitionWillBegin 103 | { 104 | id transitionCoordinator = self.presentingViewController.transitionCoordinator; 105 | 106 | [transitionCoordinator animateAlongsideTransition:^(id context) { 107 | self.dimmingView.alpha = 0.f; 108 | } completion:NULL]; 109 | } 110 | 111 | // 消失过渡完成之后调用,此时应该将视图移除,防止强引用 112 | - (void)dismissalTransitionDidEnd:(BOOL)completed 113 | { 114 | if (completed == YES) 115 | { 116 | [self.dimmingView removeFromSuperview]; 117 | self.dimmingView = nil; 118 | } 119 | } 120 | 121 | // 返回目标控制器Viewframe 122 | - (CGRect)frameOfPresentedViewInContainerView 123 | { 124 | // 这里直接按照想要的大小写死,其实这样写不好,在第二个Demo里,我们将按照苹果官方Demo,写灵活的获取方式。 125 | CGFloat height = 300.f; 126 | 127 | CGRect containerViewBounds = self.containerView.bounds; 128 | containerViewBounds.origin.y = containerViewBounds.size.height - height; 129 | containerViewBounds.size.height = height; 130 | return containerViewBounds; 131 | } 132 | 133 | 134 | 135 | // This method is invoked whenever the presentedViewController's 136 | // preferredContentSize property changes. It is also invoked just before the 137 | // presentation transition begins (prior to -presentationTransitionWillBegin). 138 | // 建议就这样重写就行,这个应该是控制器内容大小变化时,就会调用这个方法, 比如适配横竖屏幕时,翻转屏幕时 139 | // 可以使用UIContentContainer的方法来调整任何子视图控制器的大小或位置。 140 | - (void)preferredContentSizeDidChangeForChildContentContainer:(id)container 141 | { 142 | [super preferredContentSizeDidChangeForChildContentContainer:container]; 143 | 144 | if (container == self.presentedViewController) 145 | [self.containerView setNeedsLayout]; 146 | } 147 | 148 | //| ---------------------------------------------------------------------------- 149 | // This method is similar to the -viewWillLayoutSubviews method in 150 | // UIViewController. It allows the presentation controller to alter the 151 | // layout of any custom views it manages. 152 | // 153 | - (void)containerViewWillLayoutSubviews 154 | { 155 | [super containerViewWillLayoutSubviews]; 156 | self.dimmingView.frame = self.containerView.bounds; 157 | } 158 | 159 | 160 | @end 161 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo1/BViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BViewController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo1/BViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BViewController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "BViewController.h" 10 | 11 | 12 | @implementation BViewController 13 | 14 | 15 | - (IBAction)clickCloseButton:(UIButton *)sender 16 | { 17 | [self dismissViewControllerAnimated:YES completion:nil]; 18 | } 19 | 20 | 21 | - (void)dealloc 22 | { 23 | NSLog(@"%@ --> dealloc",[self class]); 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo2/SecPresentationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecPresentationController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * 实现自定义过渡动画: 13 | * 1.继承UIPresentationController 成为子类 14 | * 2.遵守UIViewControllerAnimatedTransitioning 协议 15 | * 其实也可以写成两个类,分别继承UIPresentationController和实现UIViewControllerAnimatedTransitioning协议 16 | */ 17 | @interface SecPresentationController : UIPresentationController 18 | 19 | //我们的 UIPresentationController 的子类是负责「被呈现」及「负责呈现」的 controller 以外的 controller 的 20 | //看着很绕口,说白了,在我们的例子中,它负责的仅仅是那个带渐变效果的黑色半透明背景 View。 21 | //而 UIViewControllerAnimatedTransitioning 类将会负责「被呈现」的 ViewController 的过渡动画 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo2/SecPresentationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecPresentationController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "SecPresentationController.h" 10 | 11 | // 实现 UIViewControllerAnimatedTransitioning 协议,处理动画细节处理。第三步的内容。 12 | 13 | @interface SecPresentationController () 14 | /** 黑色半透明背景 */ 15 | @property (nonatomic, strong) UIView *dimmingView; 16 | @end 17 | 18 | 19 | @implementation SecPresentationController 20 | 21 | //| ------------------------------第一步内容---------------------------------------------- 22 | #pragma mark - UIViewControllerTransitioningDelegate 23 | /* 24 | * 来告诉控制器,谁是动画主管(UIPresentationController),因为此类继承了UIPresentationController,就返回了self 25 | */ 26 | - (UIPresentationController* )presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source 27 | { 28 | return self; 29 | } 30 | 31 | // 返回的对象控制Presented时的动画 (开始动画的具体细节负责类) 32 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 33 | { 34 | return self; 35 | } 36 | // 由返回的控制器控制dismissed时的动画 (结束动画的具体细节负责类) 37 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed 38 | { 39 | return self; 40 | } 41 | 42 | 43 | 44 | //| ------------------------------第二步内容---------------------------------------------- 45 | #pragma mark - 重写UIPresentationController个别方法 46 | - (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController 47 | { 48 | self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]; 49 | 50 | if (self) { 51 | // 必须设置 presentedViewController 的 modalPresentationStyle 52 | // 在自定义动画效果的情况下,苹果强烈建议设置为 UIModalPresentationCustom 53 | presentedViewController.modalPresentationStyle = UIModalPresentationCustom; 54 | } 55 | 56 | return self; 57 | } 58 | 59 | 60 | // 呈现过渡即将开始的时候被调用的 61 | // 可以在此方法创建和设置自定义动画所需的view 62 | - (void)presentationTransitionWillBegin 63 | { 64 | // 背景遮罩 65 | UIView *dimmingView = [[UIView alloc] initWithFrame:self.containerView.bounds]; 66 | dimmingView.backgroundColor = [UIColor blackColor]; 67 | dimmingView.opaque = NO; //是否透明 68 | dimmingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 69 | [dimmingView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dimmingViewTapped:)]]; 70 | self.dimmingView = dimmingView; 71 | 72 | [self.containerView addSubview:dimmingView]; // 添加到动画容器View中。 73 | 74 | // 获取presentingViewController 的转换协调器,应该动画期间的一个类?上下文?之类的,负责动画的一个东西 75 | id transitionCoordinator = self.presentingViewController.transitionCoordinator; 76 | 77 | // 动画期间,背景View的动画方式 78 | self.dimmingView.alpha = 0.f; 79 | [transitionCoordinator animateAlongsideTransition:^(id context) { 80 | self.dimmingView.alpha = 0.4f; 81 | } completion:NULL]; 82 | } 83 | 84 | #pragma mark 点击了背景遮罩view 85 | - (void)dimmingViewTapped:(UITapGestureRecognizer*)sender 86 | { 87 | [self.presentingViewController dismissViewControllerAnimated:YES completion:NULL]; 88 | } 89 | 90 | // 在呈现过渡结束时被调用的,并且该方法提供一个布尔变量来判断过渡效果是否完成 91 | - (void)presentationTransitionDidEnd:(BOOL)completed 92 | { 93 | // 在取消动画的情况下,可能为NO,这种情况下,应该取消视图的引用,防止视图没有释放 94 | if (!completed) 95 | { 96 | self.dimmingView = nil; 97 | } 98 | } 99 | 100 | // 消失过渡即将开始的时候被调用的 101 | - (void)dismissalTransitionWillBegin 102 | { 103 | id transitionCoordinator = self.presentingViewController.transitionCoordinator; 104 | 105 | [transitionCoordinator animateAlongsideTransition:^(id context) { 106 | self.dimmingView.alpha = 0.f; 107 | } completion:NULL]; 108 | } 109 | 110 | // 消失过渡完成之后调用,此时应该将视图移除,防止强引用 111 | - (void)dismissalTransitionDidEnd:(BOOL)completed 112 | { 113 | if (completed == YES) 114 | { 115 | [self.dimmingView removeFromSuperview]; 116 | self.dimmingView = nil; 117 | } 118 | } 119 | 120 | 121 | //| --------以下四个方法,是按照苹果官方Demo里的,都是为了计算目标控制器View的frame的---------------- 122 | // 当 presentation controller 接收到 123 | // -viewWillTransitionToSize:withTransitionCoordinator: message it calls this 124 | // method to retrieve the new size for the presentedViewController's view. 125 | // The presentation controller then sends a 126 | // -viewWillTransitionToSize:withTransitionCoordinator: message to the 127 | // presentedViewController with this size as the first argument. 128 | // 129 | // Note that it is up to the presentation controller to adjust the frame 130 | // of the presented view controller's view to match this promised size. 131 | // We do this in -containerViewWillLayoutSubviews. 132 | // 133 | - (CGSize)sizeForChildContentContainer:(id)container withParentContainerSize:(CGSize)parentSize 134 | { 135 | if (container == self.presentedViewController) 136 | return ((UIViewController*)container).preferredContentSize; 137 | else 138 | return [super sizeForChildContentContainer:container withParentContainerSize:parentSize]; 139 | } 140 | 141 | //在我们的自定义呈现中,被呈现的 view 并没有完全完全填充整个屏幕, 142 | //被呈现的 view 的过渡动画之后的最终位置,是由 UIPresentationViewController 来负责定义的。 143 | //我们重载 frameOfPresentedViewInContainerView 方法来定义这个最终位置 144 | - (CGRect)frameOfPresentedViewInContainerView 145 | { 146 | CGRect containerViewBounds = self.containerView.bounds; 147 | CGSize presentedViewContentSize = [self sizeForChildContentContainer:self.presentedViewController withParentContainerSize:containerViewBounds.size]; 148 | 149 | // The presented view extends presentedViewContentSize.height points from 150 | // the bottom edge of the screen. 151 | CGRect presentedViewControllerFrame = containerViewBounds; 152 | presentedViewControllerFrame.size.height = presentedViewContentSize.height; 153 | presentedViewControllerFrame.origin.y = CGRectGetMaxY(containerViewBounds) - presentedViewContentSize.height; 154 | return presentedViewControllerFrame; 155 | } 156 | 157 | // This method is similar to the -viewWillLayoutSubviews method in 158 | // UIViewController. It allows the presentation controller to alter the 159 | // layout of any custom views it manages. 160 | // 161 | - (void)containerViewWillLayoutSubviews 162 | { 163 | [super containerViewWillLayoutSubviews]; 164 | self.dimmingView.frame = self.containerView.bounds; 165 | } 166 | 167 | 168 | // This method is invoked whenever the presentedViewController's 169 | // preferredContentSize property changes. It is also invoked just before the 170 | // presentation transition begins (prior to -presentationTransitionWillBegin). 171 | // 建议就这样重写就行,这个应该是控制器内容大小变化时,就会调用这个方法, 比如适配横竖屏幕时,翻转屏幕时 172 | // 可以使用UIContentContainer的方法来调整任何子视图控制器的大小或位置。 173 | - (void)preferredContentSizeDidChangeForChildContentContainer:(id)container 174 | { 175 | [super preferredContentSizeDidChangeForChildContentContainer:container]; 176 | 177 | if (container == self.presentedViewController) 178 | [self.containerView setNeedsLayout]; 179 | } 180 | 181 | 182 | 183 | //| ------------------------------第三步内容---------------------------------------------- 184 | #pragma mark UIViewControllerAnimatedTransitioning具体动画实现 185 | // 动画时长 186 | - (NSTimeInterval)transitionDuration:(id)transitionContext 187 | { 188 | return [transitionContext isAnimated] ? 0.55 : 0; 189 | } 190 | 191 | // 核心,动画效果的实现 192 | - (void)animateTransition:(id)transitionContext 193 | { 194 | // 1.获取源控制器、目标控制器、动画容器View 195 | UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 196 | __unused UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 197 | 198 | UIView *containerView = transitionContext.containerView; 199 | 200 | // 2. 获取源控制器、目标控制器 的View,但是注意二者在开始动画,消失动画,身份是不一样的: 201 | // 也可以直接通过上面获取控制器获取,比如:toViewController.view 202 | // For a Presentation: 203 | // fromView = The presenting view. 204 | // toView = The presented view. 205 | // For a Dismissal: 206 | // fromView = The presented view. 207 | // toView = The presenting view. 208 | UIView *toView = [transitionContext viewForKey:UITransitionContextToViewKey]; 209 | UIView *fromView = [transitionContext viewForKey:UITransitionContextFromViewKey]; 210 | 211 | [containerView addSubview:toView]; //必须添加到动画容器View上。 212 | 213 | // 判断是present 还是 dismiss 214 | BOOL isPresenting = (fromViewController == self.presentingViewController); 215 | 216 | CGFloat screenW = CGRectGetWidth(containerView.bounds); 217 | CGFloat screenH = CGRectGetHeight(containerView.bounds); 218 | 219 | // 左右留35 220 | // 上下留80 221 | 222 | // 屏幕顶部: 223 | CGFloat x = 35.f; 224 | CGFloat y = -1 * screenH; 225 | CGFloat w = screenW - x * 2; 226 | CGFloat h = screenH - 80.f * 2; 227 | CGRect topFrame = CGRectMake(x, y, w, h); 228 | 229 | // 屏幕中间: 230 | CGRect centerFrame = CGRectMake(x, 80.0, w, h); 231 | 232 | // 屏幕底部 233 | CGRect bottomFrame = CGRectMake(x, screenH + 10, w, h); //加10是因为动画果冻效果,会露出屏幕一点 234 | 235 | if (isPresenting) { 236 | toView.frame = topFrame; 237 | } 238 | 239 | NSTimeInterval duration = [self transitionDuration:transitionContext]; 240 | // duration: 动画时长 241 | // delay: 决定了动画在延迟多久之后执行 242 | // damping:速度衰减比例。取值范围0 ~ 1,值越低震动越强 243 | // velocity:初始化速度,值越高则物品的速度越快 244 | // UIViewAnimationOptionCurveEaseInOut 加速,后减速 245 | [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.7f initialSpringVelocity:0.3f options:UIViewAnimationOptionCurveEaseInOut animations:^{ 246 | if (isPresenting) 247 | toView.frame = centerFrame; 248 | else 249 | fromView.frame = bottomFrame; 250 | } completion:^(BOOL finished) { 251 | BOOL wasCancelled = [transitionContext transitionWasCancelled]; 252 | [transitionContext completeTransition:!wasCancelled]; 253 | }]; 254 | 255 | } 256 | 257 | - (void)animationEnded:(BOOL) transitionCompleted 258 | { 259 | // 动画结束... 260 | } 261 | 262 | 263 | @end 264 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo2/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo2/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | 11 | @interface SecondViewController () 12 | 13 | @end 14 | 15 | @implementation SecondViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | 21 | [self updatePreferredContentSizeWithTraitCollection:self.traitCollection]; 22 | } 23 | 24 | 25 | 26 | //| ---------------------------------------------------------------------------- 27 | - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id)coordinator 28 | { 29 | [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; 30 | 31 | // When the current trait collection changes (e.g. the device rotates), 32 | // update the preferredContentSize. 33 | [self updatePreferredContentSizeWithTraitCollection:newCollection]; 34 | } 35 | 36 | 37 | //| ---------------------------------------------------------------------------- 38 | //! Updates the receiver's preferredContentSize based on the verticalSizeClass 39 | //! of the provided \a traitCollection. 40 | // 41 | - (void)updatePreferredContentSizeWithTraitCollection:(UITraitCollection *)traitCollection 42 | { 43 | // 左右留35 44 | // 上下留80 45 | 46 | CGFloat w = self.view.bounds.size.width - 35.f * 2; 47 | CGFloat h = self.view.bounds.size.height - 80.f * 2; 48 | 49 | self.preferredContentSize = CGSizeMake(w,h); 50 | } 51 | 52 | 53 | 54 | 55 | - (void)dealloc 56 | { 57 | NSLog(@"%@ --> dealloc",[self class]); 58 | } 59 | 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo3/Demo3ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Demo3ViewController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Demo3ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CustomModalAnimation/Demo3/Demo3ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // Demo3ViewController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "Demo3ViewController.h" 10 | 11 | @interface Demo3ViewController () 12 | 13 | /** 暗色背景 */ 14 | @property (nonatomic, weak) UIView *bgView; 15 | /** 控件View */ 16 | @property (nonatomic, weak) UIView *contentView; 17 | /** 控件View */ 18 | @property (nonatomic, weak) UILabel *showLab; 19 | @end 20 | 21 | @implementation Demo3ViewController 22 | 23 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 24 | { 25 | if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { 26 | // 必须写这句话,不然看不到上一个控制器的View 27 | self.modalPresentationStyle = UIModalPresentationCustom ; 28 | [self setupUI]; 29 | } 30 | return self; 31 | } 32 | 33 | #pragma mark - 布局UI 34 | /** 布局UI */ 35 | - (void)setupUI 36 | { 37 | self.view.backgroundColor = [UIColor clearColor]; 38 | 39 | UIView *bgView = [[UIView alloc] init]; 40 | bgView.backgroundColor = [UIColor colorWithRed:0.25 green:0.25 blue:0.25 alpha:0.5f]; 41 | [self.view addSubview:bgView]; 42 | self.bgView = bgView; 43 | self.bgView.alpha = 0.0f; 44 | 45 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickBgView)]; 46 | [bgView addGestureRecognizer:tap]; 47 | 48 | 49 | UIView *cView = [[UIView alloc] init]; 50 | cView.backgroundColor = [UIColor whiteColor]; 51 | [self.view addSubview:cView]; 52 | self.contentView = cView; 53 | 54 | UILabel *lab = [[UILabel alloc] initWithFrame:CGRectZero]; 55 | lab.frame = CGRectMake(10.f, 0, CGRectGetWidth([UIScreen mainScreen].bounds) - 20.f, 300.f); 56 | lab.text = @"在此View上添加自己的具体实现,通过viewWillAppear和clickBgVie,可以自定义出很绚的动画效果,这种动画方式只是给大家提供一种思路,实现问题的方法有很多,有时候很多效果感觉很难实现,也许它用了一些障眼法之类的。我比较喜欢投机取巧的方式实现一些效果的,不过对于新技术,还是要积极去学习的,本Demo没有使用Swift,但是代码注释很详细,Swift对应方法和步骤敲出来即可!欢迎点赞。"; 57 | lab.numberOfLines = 0 ; 58 | lab.font = [UIFont systemFontOfSize:16.f]; 59 | [cView addSubview:lab]; 60 | self.showLab = lab; 61 | 62 | cView.layer.borderColor = [UIColor redColor].CGColor; 63 | cView.layer.borderWidth = 1.0 ; 64 | } 65 | 66 | 67 | #pragma mark - 在此方法做动画呈现 68 | - (void)viewWillAppear:(BOOL)animated 69 | { 70 | [super viewWillAppear:animated]; 71 | 72 | self.bgView.frame = [UIScreen mainScreen].bounds; 73 | self.contentView.frame = CGRectMake(0,[UIScreen mainScreen].bounds.size.height, CGRectGetWidth([UIScreen mainScreen].bounds), 300.0); 74 | 75 | 76 | [UIView animateWithDuration:0.4 delay:0 usingSpringWithDamping:0.95 initialSpringVelocity:0.05 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 77 | 78 | self.bgView.alpha = 1.0f ; 79 | 80 | self.contentView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height - 300.f, CGRectGetWidth([UIScreen mainScreen].bounds), 300.0f); 81 | 82 | } completion:^(BOOL finished) { 83 | }]; 84 | } 85 | 86 | 87 | #pragma mark - 消失 88 | - (void)clickBgView 89 | { 90 | [UIView animateWithDuration:0.4 delay:0 usingSpringWithDamping:0.95 initialSpringVelocity:0.05 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 91 | 92 | self.bgView.alpha = 0.0f ; 93 | self.contentView.frame = CGRectMake(0,[UIScreen mainScreen].bounds.size.height, CGRectGetWidth([UIScreen mainScreen].bounds), 300.0); 94 | 95 | } completion:^(BOOL finished) { 96 | // 动画Animated必须是NO,不然消失之后,会有0.35s时间,再点击无效 97 | [self dismissViewControllerAnimated:NO completion:nil]; 98 | }]; 99 | } 100 | 101 | 102 | 103 | // 这里主动释放一些空间,加速内存的释放,防止有时候消失之后,再点不出来。 104 | - (void)dealloc 105 | { 106 | NSLog(@"%@ --> dealloc",[self class]); 107 | [self.bgView removeFromSuperview]; 108 | self.bgView = nil; 109 | [self.contentView removeFromSuperview]; 110 | self.contentView = nil; 111 | } 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /CustomModalAnimation/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /CustomModalAnimation/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /CustomModalAnimation/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "BViewController.h" 12 | #import "BCustomPresentationController.h" 13 | 14 | #import "SecondViewController.h" 15 | #import "SecPresentationController.h" 16 | 17 | #import "Demo3ViewController.h" 18 | 19 | @interface ViewController () 20 | @property (weak, nonatomic) IBOutlet UIButton *demo1Btn; 21 | @property (weak, nonatomic) IBOutlet UIButton *demo2Btn; 22 | @property (weak, nonatomic) IBOutlet UIButton *demo3Btn; 23 | 24 | @end 25 | 26 | @implementation ViewController 27 | 28 | - (void)viewDidLoad 29 | { 30 | [super viewDidLoad]; 31 | _demo1Btn.layer.borderColor = [UIColor redColor].CGColor; 32 | _demo1Btn.layer.borderWidth = 1.0 ; 33 | _demo2Btn.layer.borderColor = [UIColor purpleColor].CGColor; 34 | _demo2Btn.layer.borderWidth = 1.0 ; 35 | _demo3Btn.layer.borderColor = [UIColor orangeColor].CGColor; 36 | _demo3Btn.layer.borderWidth = 1.0 ; 37 | } 38 | 39 | 40 | #pragma mark - Demo1 41 | - (IBAction)clickDemo1:(UIButton *)sender 42 | { 43 | BViewController *toVC = [self.storyboard instantiateViewControllerWithIdentifier:@"BViewController"]; 44 | 45 | BCustomPresentationController *presentationC = [[BCustomPresentationController alloc] initWithPresentedViewController:toVC presentingViewController:self]; 46 | toVC.transitioningDelegate = presentationC ; // 指定自定义modal动画的代理 47 | 48 | [self presentViewController:toVC animated:YES completion:nil]; 49 | 50 | // animated必须是YES,因为此Demo1没有自己实现动画细节协议。 51 | } 52 | 53 | #pragma mark - Demo2 54 | - (IBAction)clickDemo2:(UIButton *)sender 55 | { 56 | SecondViewController *toVC = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"]; 57 | 58 | SecPresentationController *presentationC = [[SecPresentationController alloc] initWithPresentedViewController:toVC presentingViewController:self]; 59 | toVC.transitioningDelegate = presentationC ; // 指定自定义modal动画的代理 60 | 61 | [self presentViewController:toVC animated:YES completion:nil]; 62 | } 63 | 64 | #pragma mark - Demo3 65 | - (IBAction)clickDemo3:(UIButton *)sender 66 | { 67 | Demo3ViewController *vc = [[Demo3ViewController alloc] init]; 68 | [self presentViewController:vc animated:NO completion:nil]; 69 | 70 | // animated:NO 必须是no 71 | } 72 | 73 | 74 | 75 | 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /CustomModalAnimation/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CustomModalAnimation 4 | // 5 | // Created by 侯万 on 2017/3/9. 6 | // Copyright © 2017年 HW. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![效果图](https://github.com/HouWan/CustomModalAnimation/blob/master/iOSApp3.gif) 3 | 4 | ### 使用`UIPresentationController`自定义modal转场动画。 5 | ### 简书讲解地址: [点我](http://www.jianshu.com/p/a7335474651c) 6 | 7 | # 小侯爷 ~~ 佛祖保佑 永无BUG ~~ 小侯爷 8 | ``` 9 | 10 | _ooOoo_ 11 | o8888888o 12 | 88" . "88 13 | (| -_- |) 14 | O\ = /O 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 | ( )c~c~~@~@ )- - &&\ \ 45 | C >/ \< |&/ 46 | \_O/ - 哇塞 _`*-'_/ / 47 | ,- >o<-. / ____ _/ 48 | / \/ \ / /\ _)_) 49 | / /| | |\ \ / / ) | 50 | \ \| | |/ / \ \ / | 51 | \_\ | |_/ \ \_ | 52 | /_/`___|_\ /_/\____| 53 | | | | \ \| 54 | | | | `. ) 55 | | | | / / 56 | |__|_|_ /_/| 57 | (____)_) |\_\_ 58 | ``` 59 | 60 | 61 | # 苦逼程序员专用 -------------------------------------------------------------------------------- /iOSApp3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HouWan/CustomModalAnimation/561d9a4b568b9d696b5071ae8b510a224ccc2206/iOSApp3.gif --------------------------------------------------------------------------------