├── .gitignore ├── Demo ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── test.imageset │ │ ├── Contents.json │ │ └── test.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Demo.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── Demo.xcscheme ├── Info.plist ├── MDAppDelegate.h ├── MDAppDelegate.m ├── MDCustomImageViewController.h ├── MDCustomImageViewController.m ├── MDCustomViewController.h ├── MDCustomViewController.m ├── MDPresentedViewController.h ├── MDPresentedViewController.m ├── MDPresentionControlViewController.h ├── MDPresentionControlViewController.m ├── MDRootViewController.h ├── MDRootViewController.m ├── MDVerticalSwipPopViewController.h ├── MDVerticalSwipPopViewController.m └── main.m ├── ImagePreview ├── MDImageDismissInteractionController.h ├── MDImageDismissInteractionController.m ├── MDImageDraggingDismissInteractionController.h ├── MDImageDraggingDismissInteractionController.m ├── MDImageViewController.h ├── MDImageViewController.m ├── MDImageZoomAnimationController.h ├── MDImageZoomAnimationController.m └── MDTransitioning+ImagePreview.h ├── Info.plist ├── LICENSE ├── MDTransitioning.md ├── MDTransitioning.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── MDTransitioning.xcscheme │ └── MDTransitioning_ImagePriview.xcscheme ├── MDTransitioning.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── MDTransitioning ├── MDAnimatedTransitioning.h ├── MDInteractionController.h ├── MDInteractiveTransitioning.h ├── MDNavigationAnimationController.h ├── MDNavigationAnimationController.m ├── MDNavigationControllerDelegate.h ├── MDNavigationControllerDelegate.m ├── MDPopInteractionController.h ├── MDPopInteractionController.m ├── MDPresentionAnimationController.h ├── MDPresentionAnimationController.m ├── MDPresentionControllerDelegate.h ├── MDPresentionControllerDelegate.m ├── MDScaleNavigationAnimationController.h ├── MDScaleNavigationAnimationController.m ├── MDSwipeInteractionController.h ├── MDSwipeInteractionController.m ├── MDTransitioning+Private.h ├── MDTransitioning+Private.m ├── MDTransitioning.h ├── MDVerticalSwipDismissInteractionController.h ├── MDVerticalSwipDismissInteractionController.m ├── MDVerticalSwipInteractionController.h ├── MDVerticalSwipInteractionController.m ├── MDVerticalSwipPopInteractionController.h ├── MDVerticalSwipPopInteractionController.m ├── UIViewController+MDNavigationTransitioning.h ├── UIViewController+MDNavigationTransitioning.m ├── UIViewController+MDPresentionTransitioning.h └── UIViewController+MDPresentionTransitioning.m ├── README.md └── snapshots ├── custom_present.gif ├── custom_push.gif ├── image_present.gif ├── scale_push.gif ├── system_present.gif ├── system_push.gif └── vertical_pop.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /Demo/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 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/test.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "test.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/test.imageset/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/Demo/Assets.xcassets/test.imageset/test.png -------------------------------------------------------------------------------- /Demo/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 | -------------------------------------------------------------------------------- /Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 86 | 94 | 102 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 139 | 147 | 155 | 156 | 157 | 158 | 159 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 083D02191F3057F400D1E530 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 083D020B1F3057F400D1E530 /* Assets.xcassets */; }; 11 | 083D021A1F3057F400D1E530 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 083D020D1F3057F400D1E530 /* LaunchScreen.storyboard */; }; 12 | 083D021B1F3057F400D1E530 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 083D020F1F3057F400D1E530 /* Main.storyboard */; }; 13 | 083D021D1F3057F400D1E530 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 083D02121F3057F400D1E530 /* main.m */; }; 14 | 083D021E1F3057F400D1E530 /* MDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 083D02141F3057F400D1E530 /* MDAppDelegate.m */; }; 15 | 083D021F1F3057F400D1E530 /* MDPresentedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 083D02161F3057F400D1E530 /* MDPresentedViewController.m */; }; 16 | 083D02201F3057F400D1E530 /* MDPresentionControlViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 083D02181F3057F400D1E530 /* MDPresentionControlViewController.m */; }; 17 | 083D02311F30626D00D1E530 /* MDCustomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 083D02301F30626D00D1E530 /* MDCustomViewController.m */; }; 18 | 08555F3D1F31775600591B10 /* MDTransitioning.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08555F3C1F31775600591B10 /* MDTransitioning.framework */; }; 19 | 08555F3E1F31775600591B10 /* MDTransitioning.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08555F3C1F31775600591B10 /* MDTransitioning.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 20 | 08555F401F31775600591B10 /* MDTransitioning_ImagePriview.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08555F3F1F31775600591B10 /* MDTransitioning_ImagePriview.framework */; }; 21 | 08555F411F31775600591B10 /* MDTransitioning_ImagePriview.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08555F3F1F31775600591B10 /* MDTransitioning_ImagePriview.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | 0856B4AA1F72CBDE00905F3A /* MDCustomImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0856B4A91F72CBDE00905F3A /* MDCustomImageViewController.m */; }; 23 | 0856B4AD1F72D06300905F3A /* MDVerticalSwipPopViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0856B4AC1F72D06300905F3A /* MDVerticalSwipPopViewController.m */; }; 24 | 0856B4B31F72D2AC00905F3A /* MDRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0856B4B21F72D2AC00905F3A /* MDRootViewController.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXCopyFilesBuildPhase section */ 28 | 08555F3B1F31773800591B10 /* Embed Frameworks */ = { 29 | isa = PBXCopyFilesBuildPhase; 30 | buildActionMask = 2147483647; 31 | dstPath = ""; 32 | dstSubfolderSpec = 10; 33 | files = ( 34 | 08555F411F31775600591B10 /* MDTransitioning_ImagePriview.framework in Embed Frameworks */, 35 | 08555F3E1F31775600591B10 /* MDTransitioning.framework in Embed Frameworks */, 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXCopyFilesBuildPhase section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 083D017C1F30577E00D1E530 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 083D020B1F3057F400D1E530 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 083D020E1F3057F400D1E530 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 46 | 083D02101F3057F400D1E530 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 47 | 083D02111F3057F400D1E530 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 083D02121F3057F400D1E530 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 083D02131F3057F400D1E530 /* MDAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDAppDelegate.h; sourceTree = ""; }; 50 | 083D02141F3057F400D1E530 /* MDAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDAppDelegate.m; sourceTree = ""; }; 51 | 083D02151F3057F400D1E530 /* MDPresentedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDPresentedViewController.h; sourceTree = ""; }; 52 | 083D02161F3057F400D1E530 /* MDPresentedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDPresentedViewController.m; sourceTree = ""; }; 53 | 083D02171F3057F400D1E530 /* MDPresentionControlViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDPresentionControlViewController.h; sourceTree = ""; }; 54 | 083D02181F3057F400D1E530 /* MDPresentionControlViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDPresentionControlViewController.m; sourceTree = ""; }; 55 | 083D022F1F30626D00D1E530 /* MDCustomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDCustomViewController.h; sourceTree = ""; }; 56 | 083D02301F30626D00D1E530 /* MDCustomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDCustomViewController.m; sourceTree = ""; }; 57 | 08555F3C1F31775600591B10 /* MDTransitioning.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MDTransitioning.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 08555F3F1F31775600591B10 /* MDTransitioning_ImagePriview.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MDTransitioning_ImagePriview.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 0856B4A81F72CBDE00905F3A /* MDCustomImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDCustomImageViewController.h; sourceTree = ""; }; 60 | 0856B4A91F72CBDE00905F3A /* MDCustomImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDCustomImageViewController.m; sourceTree = ""; }; 61 | 0856B4AB1F72D06300905F3A /* MDVerticalSwipPopViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDVerticalSwipPopViewController.h; sourceTree = ""; }; 62 | 0856B4AC1F72D06300905F3A /* MDVerticalSwipPopViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDVerticalSwipPopViewController.m; sourceTree = ""; }; 63 | 0856B4B11F72D2AC00905F3A /* MDRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MDRootViewController.h; sourceTree = ""; }; 64 | 0856B4B21F72D2AC00905F3A /* MDRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MDRootViewController.m; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | 083D01791F30577E00D1E530 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | 08555F401F31775600591B10 /* MDTransitioning_ImagePriview.framework in Frameworks */, 73 | 08555F3D1F31775600591B10 /* MDTransitioning.framework in Frameworks */, 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | /* End PBXFrameworksBuildPhase section */ 78 | 79 | /* Begin PBXGroup section */ 80 | 083D01731F30577E00D1E530 = { 81 | isa = PBXGroup; 82 | children = ( 83 | 08555F3F1F31775600591B10 /* MDTransitioning_ImagePriview.framework */, 84 | 08555F3C1F31775600591B10 /* MDTransitioning.framework */, 85 | 083D020B1F3057F400D1E530 /* Assets.xcassets */, 86 | 083D020D1F3057F400D1E530 /* LaunchScreen.storyboard */, 87 | 083D020F1F3057F400D1E530 /* Main.storyboard */, 88 | 083D02111F3057F400D1E530 /* Info.plist */, 89 | 083D02121F3057F400D1E530 /* main.m */, 90 | 083D02131F3057F400D1E530 /* MDAppDelegate.h */, 91 | 083D02141F3057F400D1E530 /* MDAppDelegate.m */, 92 | 0856B4B11F72D2AC00905F3A /* MDRootViewController.h */, 93 | 0856B4B21F72D2AC00905F3A /* MDRootViewController.m */, 94 | 083D02171F3057F400D1E530 /* MDPresentionControlViewController.h */, 95 | 083D02181F3057F400D1E530 /* MDPresentionControlViewController.m */, 96 | 083D022F1F30626D00D1E530 /* MDCustomViewController.h */, 97 | 083D02301F30626D00D1E530 /* MDCustomViewController.m */, 98 | 0856B4A81F72CBDE00905F3A /* MDCustomImageViewController.h */, 99 | 0856B4A91F72CBDE00905F3A /* MDCustomImageViewController.m */, 100 | 0856B4AB1F72D06300905F3A /* MDVerticalSwipPopViewController.h */, 101 | 0856B4AC1F72D06300905F3A /* MDVerticalSwipPopViewController.m */, 102 | 083D02151F3057F400D1E530 /* MDPresentedViewController.h */, 103 | 083D02161F3057F400D1E530 /* MDPresentedViewController.m */, 104 | 083D017D1F30577E00D1E530 /* Products */, 105 | 083D02211F30585000D1E530 /* Frameworks */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 083D017D1F30577E00D1E530 /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 083D017C1F30577E00D1E530 /* Demo.app */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | 083D02211F30585000D1E530 /* Frameworks */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | ); 121 | name = Frameworks; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | 083D017B1F30577E00D1E530 /* Demo */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = 083D01931F30577E00D1E530 /* Build configuration list for PBXNativeTarget "Demo" */; 130 | buildPhases = ( 131 | 083D01781F30577E00D1E530 /* Sources */, 132 | 083D01791F30577E00D1E530 /* Frameworks */, 133 | 083D017A1F30577E00D1E530 /* Resources */, 134 | 08555F3B1F31773800591B10 /* Embed Frameworks */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | ); 140 | name = Demo; 141 | productName = Demo; 142 | productReference = 083D017C1F30577E00D1E530 /* Demo.app */; 143 | productType = "com.apple.product-type.application"; 144 | }; 145 | /* End PBXNativeTarget section */ 146 | 147 | /* Begin PBXProject section */ 148 | 083D01741F30577E00D1E530 /* Project object */ = { 149 | isa = PBXProject; 150 | attributes = { 151 | LastUpgradeCheck = 0930; 152 | ORGANIZATIONNAME = markejave; 153 | TargetAttributes = { 154 | 083D017B1F30577E00D1E530 = { 155 | CreatedOnToolsVersion = 8.3.3; 156 | DevelopmentTeam = 79E68V4GS2; 157 | ProvisioningStyle = Manual; 158 | }; 159 | }; 160 | }; 161 | buildConfigurationList = 083D01771F30577E00D1E530 /* Build configuration list for PBXProject "Demo" */; 162 | compatibilityVersion = "Xcode 3.2"; 163 | developmentRegion = English; 164 | hasScannedForEncodings = 0; 165 | knownRegions = ( 166 | en, 167 | Base, 168 | ); 169 | mainGroup = 083D01731F30577E00D1E530; 170 | productRefGroup = 083D017D1F30577E00D1E530 /* Products */; 171 | projectDirPath = ""; 172 | projectRoot = ""; 173 | targets = ( 174 | 083D017B1F30577E00D1E530 /* Demo */, 175 | ); 176 | }; 177 | /* End PBXProject section */ 178 | 179 | /* Begin PBXResourcesBuildPhase section */ 180 | 083D017A1F30577E00D1E530 /* Resources */ = { 181 | isa = PBXResourcesBuildPhase; 182 | buildActionMask = 2147483647; 183 | files = ( 184 | 083D021B1F3057F400D1E530 /* Main.storyboard in Resources */, 185 | 083D02191F3057F400D1E530 /* Assets.xcassets in Resources */, 186 | 083D021A1F3057F400D1E530 /* LaunchScreen.storyboard in Resources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXResourcesBuildPhase section */ 191 | 192 | /* Begin PBXSourcesBuildPhase section */ 193 | 083D01781F30577E00D1E530 /* Sources */ = { 194 | isa = PBXSourcesBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | 0856B4AA1F72CBDE00905F3A /* MDCustomImageViewController.m in Sources */, 198 | 083D021D1F3057F400D1E530 /* main.m in Sources */, 199 | 083D02201F3057F400D1E530 /* MDPresentionControlViewController.m in Sources */, 200 | 083D021F1F3057F400D1E530 /* MDPresentedViewController.m in Sources */, 201 | 083D02311F30626D00D1E530 /* MDCustomViewController.m in Sources */, 202 | 0856B4B31F72D2AC00905F3A /* MDRootViewController.m in Sources */, 203 | 083D021E1F3057F400D1E530 /* MDAppDelegate.m in Sources */, 204 | 0856B4AD1F72D06300905F3A /* MDVerticalSwipPopViewController.m in Sources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXSourcesBuildPhase section */ 209 | 210 | /* Begin PBXVariantGroup section */ 211 | 083D020D1F3057F400D1E530 /* LaunchScreen.storyboard */ = { 212 | isa = PBXVariantGroup; 213 | children = ( 214 | 083D020E1F3057F400D1E530 /* Base */, 215 | ); 216 | name = LaunchScreen.storyboard; 217 | path = Base.lproj; 218 | sourceTree = ""; 219 | }; 220 | 083D020F1F3057F400D1E530 /* Main.storyboard */ = { 221 | isa = PBXVariantGroup; 222 | children = ( 223 | 083D02101F3057F400D1E530 /* Base */, 224 | ); 225 | name = Main.storyboard; 226 | path = Base.lproj; 227 | sourceTree = ""; 228 | }; 229 | /* End PBXVariantGroup section */ 230 | 231 | /* Begin XCBuildConfiguration section */ 232 | 083D01911F30577E00D1E530 /* Debug */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | ALWAYS_SEARCH_USER_PATHS = NO; 236 | CLANG_ANALYZER_NONNULL = YES; 237 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 238 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 239 | CLANG_CXX_LIBRARY = "libc++"; 240 | CLANG_ENABLE_MODULES = YES; 241 | CLANG_ENABLE_OBJC_ARC = YES; 242 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 243 | CLANG_WARN_BOOL_CONVERSION = YES; 244 | CLANG_WARN_COMMA = YES; 245 | CLANG_WARN_CONSTANT_CONVERSION = YES; 246 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 248 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = dwarf; 265 | ENABLE_STRICT_OBJC_MSGSEND = YES; 266 | ENABLE_TESTABILITY = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_DYNAMIC_NO_PIC = NO; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_OPTIMIZATION_LEVEL = 0; 271 | GCC_PREPROCESSOR_DEFINITIONS = ( 272 | "DEBUG=1", 273 | "$(inherited)", 274 | ); 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 282 | MTL_ENABLE_DEBUG_INFO = YES; 283 | ONLY_ACTIVE_ARCH = YES; 284 | SDKROOT = iphoneos; 285 | TARGETED_DEVICE_FAMILY = "1,2"; 286 | }; 287 | name = Debug; 288 | }; 289 | 083D01921F30577E00D1E530 /* Release */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ALWAYS_SEARCH_USER_PATHS = NO; 293 | CLANG_ANALYZER_NONNULL = YES; 294 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 295 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 296 | CLANG_CXX_LIBRARY = "libc++"; 297 | CLANG_ENABLE_MODULES = YES; 298 | CLANG_ENABLE_OBJC_ARC = YES; 299 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 300 | CLANG_WARN_BOOL_CONVERSION = YES; 301 | CLANG_WARN_COMMA = YES; 302 | CLANG_WARN_CONSTANT_CONVERSION = YES; 303 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 304 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 305 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INFINITE_RECURSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 312 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 315 | CLANG_WARN_STRICT_PROTOTYPES = YES; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 322 | ENABLE_NS_ASSERTIONS = NO; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | GCC_C_LANGUAGE_STANDARD = gnu99; 325 | GCC_NO_COMMON_BLOCKS = YES; 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 333 | MTL_ENABLE_DEBUG_INFO = NO; 334 | SDKROOT = iphoneos; 335 | TARGETED_DEVICE_FAMILY = "1,2"; 336 | VALIDATE_PRODUCT = YES; 337 | }; 338 | name = Release; 339 | }; 340 | 083D01941F30577E00D1E530 /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 344 | DEVELOPMENT_TEAM = 79E68V4GS2; 345 | INFOPLIST_FILE = Info.plist; 346 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 347 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 348 | PRODUCT_BUNDLE_IDENTIFIER = com.markejave.Demo; 349 | PRODUCT_NAME = "$(TARGET_NAME)"; 350 | PROVISIONING_PROFILE = "c0d66c64-1571-4a6f-8b6c-afac376c527e"; 351 | PROVISIONING_PROFILE_SPECIFIER = "all apps development profile"; 352 | }; 353 | name = Debug; 354 | }; 355 | 083D01951F30577E00D1E530 /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 359 | DEVELOPMENT_TEAM = 79E68V4GS2; 360 | INFOPLIST_FILE = Info.plist; 361 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 362 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 363 | PRODUCT_BUNDLE_IDENTIFIER = com.markejave.Demo; 364 | PRODUCT_NAME = "$(TARGET_NAME)"; 365 | PROVISIONING_PROFILE = "c57274e6-e540-4463-b42f-6d513d4aaf58"; 366 | PROVISIONING_PROFILE_SPECIFIER = "all apps development profile"; 367 | }; 368 | name = Release; 369 | }; 370 | /* End XCBuildConfiguration section */ 371 | 372 | /* Begin XCConfigurationList section */ 373 | 083D01771F30577E00D1E530 /* Build configuration list for PBXProject "Demo" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | 083D01911F30577E00D1E530 /* Debug */, 377 | 083D01921F30577E00D1E530 /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | 083D01931F30577E00D1E530 /* Build configuration list for PBXNativeTarget "Demo" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | 083D01941F30577E00D1E530 /* Debug */, 386 | 083D01951F30577E00D1E530 /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | /* End XCConfigurationList section */ 392 | }; 393 | rootObject = 083D01741F30577E00D1E530 /* Project object */; 394 | } 395 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/xcshareddata/xcschemes/Demo.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 | -------------------------------------------------------------------------------- /Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | 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 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Demo/MDAppDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDAppDelegate : UIResponder 24 | 25 | @property (strong, nonatomic) UIWindow *window; 26 | 27 | 28 | @end 29 | 30 | -------------------------------------------------------------------------------- /Demo/MDAppDelegate.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDAppDelegate.h" 22 | 23 | @interface MDAppDelegate () 24 | 25 | @end 26 | 27 | @implementation MDAppDelegate 28 | 29 | 30 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 31 | // Override point for customization after application launch. 32 | 33 | return YES; 34 | } 35 | 36 | 37 | - (void)applicationWillResignActive:(UIApplication *)application { 38 | // 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. 39 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 40 | } 41 | 42 | 43 | - (void)applicationDidEnterBackground:(UIApplication *)application { 44 | // 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. 45 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 46 | } 47 | 48 | 49 | - (void)applicationWillEnterForeground:(UIApplication *)application { 50 | // 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. 51 | } 52 | 53 | 54 | - (void)applicationDidBecomeActive:(UIApplication *)application { 55 | // 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. 56 | } 57 | 58 | 59 | - (void)applicationWillTerminate:(UIApplication *)application { 60 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 61 | } 62 | 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /Demo/MDCustomImageViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDCustomImageViewController : MDImageViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/MDCustomImageViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDCustomImageViewController.m 3 | // Demo 4 | // 5 | // Created by 徐 林峰 on 2017/9/21. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "MDCustomImageViewController.h" 12 | 13 | @interface MDCustomImageViewController () 14 | 15 | @end 16 | 17 | @implementation MDCustomImageViewController 18 | 19 | - (id)initWithImage:(UIImage *)image;{ 20 | if (self = [super initWithImage:image]) { 21 | self.modalPresentationStyle = UIModalPresentationFullScreen; 22 | } 23 | return self; 24 | } 25 | 26 | #pragma mark - MDPresentionController 27 | 28 | - (id)animationForPresentionOperation:(MDPresentionAnimatedOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 29 | if (operation == MDPresentionAnimatedOperationPresent) { 30 | MDImageZoomAnimationController *controller = [MDImageZoomAnimationController animationForPresentOperation:operation fromViewController:fromViewController toViewController:toViewController]; 31 | controller.hideReferenceImageViewWhenZoomIn = NO; 32 | return controller; 33 | } else { 34 | return [[MDPresentionAnimationController alloc] initWithPresentionAnimatedOperation:operation fromViewController:fromViewController toViewController:toViewController]; 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Demo/MDCustomViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDCustomViewController : UIViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/MDCustomViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDCustomViewController.h" 22 | #import 23 | 24 | @interface MDCustomViewController () 25 | 26 | @end 27 | 28 | @implementation MDCustomViewController 29 | 30 | - (void)loadView{ 31 | [super loadView]; 32 | 33 | self.view.backgroundColor = [UIColor blueColor]; 34 | } 35 | 36 | #pragma mark - MDNavigationPopController 37 | 38 | - (id)animationForNavigationOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 39 | return [[MDScaleNavigationAnimationController alloc] initWithNavigationControllerOperation:operation fromViewController:fromViewController toViewController:toViewController]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Demo/MDPresentedViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDPresentedViewController : UIViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/MDPresentedViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDPresentedViewController.h" 23 | 24 | @interface MDPresentedViewController () 25 | 26 | @end 27 | 28 | @implementation MDPresentedViewController 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | // Do any additional setup after loading the view. 33 | 34 | self.view.backgroundColor = [UIColor redColor]; 35 | 36 | UIButton *dismissButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; 37 | [dismissButton setTitle:@"dismiss" forState:UIControlStateNormal]; 38 | [dismissButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 39 | 40 | [dismissButton addTarget:self action:@selector(didClickDismiss:) forControlEvents:UIControlEventTouchUpInside]; 41 | 42 | [[self view] addSubview:dismissButton]; 43 | 44 | if ([self transitioningDelegate]) { 45 | MDVerticalSwipDismissInteractionController *interactionController = [MDVerticalSwipDismissInteractionController interactionControllerWithViewController:self]; 46 | interactionController.verticalTranslation = CGRectGetHeight([[self view] bounds]); 47 | 48 | self.presentionInteractionController = interactionController; 49 | } 50 | } 51 | 52 | #pragma mark - actions 53 | 54 | - (IBAction)didClickDismiss:(id)sender{ 55 | [self dismissViewControllerAnimated:YES completion:nil]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Demo/MDPresentionControlViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDPresentionControlViewController : UIViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/MDPresentionControlViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDPresentionControlViewController.h" 23 | #import "MDPresentedViewController.h" 24 | #import "MDCustomImageViewController.h" 25 | 26 | @interface MDPresentionControlViewController () 27 | 28 | @property (weak, nonatomic) IBOutlet UIImageView *imageView; 29 | 30 | @end 31 | 32 | @implementation MDPresentionControlViewController 33 | 34 | - (void)loadView{ 35 | [super loadView]; 36 | 37 | self.view.backgroundColor = [UIColor brownColor]; 38 | } 39 | 40 | #pragma mark - actions 41 | 42 | - (IBAction)didClickBackButton:(id)sender { 43 | [[self navigationController] popViewControllerAnimated:YES]; 44 | } 45 | 46 | - (IBAction)didClickImageButton:(id)sender { 47 | MDImageViewController *imageViewController = [[MDImageViewController alloc] initWithImage:[[self imageView] image]]; 48 | imageViewController.transitioningDelegate = [MDPresentionControllerDelegate delegateWithReferenceViewController:self]; 49 | 50 | [self presentViewController:imageViewController animated:YES completion:nil]; 51 | } 52 | 53 | - (IBAction)didClickSystemPresent:(id)sender { 54 | MDPresentedViewController *presentViewController = [MDPresentedViewController new]; 55 | [self presentViewController:presentViewController animated:YES completion:nil]; 56 | } 57 | 58 | - (IBAction)didClickPresent:(id)sender { 59 | MDPresentedViewController *presentViewController = [MDPresentedViewController new]; 60 | presentViewController.transitioningDelegate = [MDPresentionControllerDelegate delegateWithReferenceViewController:self]; 61 | 62 | [self presentViewController:presentViewController animated:YES completion:nil]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Demo/MDRootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDRootViewController.h 3 | // Demo 4 | // 5 | // Created by 徐 林峰 on 2017/9/21. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MDRootViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Demo/MDRootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDRootViewController.m 3 | // Demo 4 | // 5 | // Created by 徐 林峰 on 2017/9/21. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MDRootViewController.h" 11 | #import "MDCustomViewController.h" 12 | #import "MDPresentionControlViewController.h" 13 | #import "MDVerticalSwipPopViewController.h" 14 | 15 | @interface MDRootViewController () 16 | 17 | @property (nonatomic, strong) UIColor *backgroundColor; 18 | 19 | @end 20 | 21 | @implementation MDRootViewController 22 | 23 | - (void)viewDidLoad{ 24 | [super viewDidLoad]; 25 | 26 | if ([self backgroundColor]) self.view.backgroundColor = [UIColor brownColor]; 27 | 28 | self.navigationController.navigationBarHidden = YES; 29 | } 30 | 31 | - (void)didReceiveMemoryWarning { 32 | [super didReceiveMemoryWarning]; 33 | // Dispose of any resources that can be recreated. 34 | } 35 | 36 | - (IBAction)didClickSystemPush:(id)sender { 37 | MDPresentionControlViewController * viewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"MDPresentionControlViewController"]; 38 | viewController.allowPopInteractive = NO; 39 | viewController.hidesBottomBarWhenPushed = YES; 40 | 41 | self.navigationController.delegate = nil; 42 | [[self navigationController] pushViewController:viewController animated:YES]; 43 | } 44 | 45 | - (IBAction)didClickNormalPush:(id)sender { 46 | MDRootViewController *viewController = [MDRootViewController new]; 47 | viewController.backgroundColor = [UIColor brownColor]; 48 | viewController.hidesBottomBarWhenPushed = YES; 49 | 50 | self.navigationController.allowPushAnimation = YES; 51 | self.navigationController.delegate = [MDNavigationControllerDelegate defaultDelegate]; 52 | 53 | [[self navigationController] pushViewController:viewController animated:YES]; 54 | } 55 | 56 | - (IBAction)didClickScalePush:(id)sender { 57 | MDCustomViewController *viewController = [MDCustomViewController new]; 58 | viewController.hidesBottomBarWhenPushed = YES; 59 | 60 | self.navigationController.allowPushAnimation = YES; 61 | self.navigationController.delegate = [MDNavigationControllerDelegate defaultDelegate]; 62 | 63 | [[self navigationController] pushViewController:viewController animated:YES]; 64 | } 65 | 66 | - (IBAction)didClickVerticalPush:(id)sender { 67 | MDVerticalSwipPopViewController *viewController = [MDVerticalSwipPopViewController new]; 68 | viewController.hidesBottomBarWhenPushed = YES; 69 | 70 | self.navigationController.allowPushAnimation = YES; 71 | self.navigationController.delegate = [MDNavigationControllerDelegate defaultDelegate]; 72 | 73 | [[self navigationController] pushViewController:viewController animated:YES]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Demo/MDVerticalSwipPopViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDVerticalSwipPopViewController : UIViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Demo/MDVerticalSwipPopViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipPopViewController.m 3 | // Demo 4 | // 5 | // Created by 徐 林峰 on 2017/9/21. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MDVerticalSwipPopViewController.h" 11 | 12 | @interface MDVerticalSwipPopViewController () 13 | 14 | @end 15 | 16 | @implementation MDVerticalSwipPopViewController 17 | 18 | - (void)loadView{ 19 | [super loadView]; 20 | 21 | self.view.backgroundColor = [UIColor greenColor]; 22 | } 23 | 24 | - (id)requirePopInteractionController{ 25 | return [MDVerticalSwipPopInteractionController interactionControllerWithViewController:self]; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Demo/main.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDAppDelegate.h" 23 | 24 | int main(int argc, char * argv[]) { 25 | @autoreleasepool { 26 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([MDAppDelegate class])); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ImagePreview/MDImageDismissInteractionController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDImageDismissInteractionController : MDSwipeInteractionController 24 | 25 | // The max distance of translation, default is controller.view.width / 3.f. 26 | @property (nonatomic, assign) CGFloat translation; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ImagePreview/MDImageDismissInteractionController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDImageDismissInteractionController.h" 22 | #import "MDImageZoomAnimationController.h" 23 | 24 | @implementation MDImageDismissInteractionController 25 | 26 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 27 | if (self = [super initWithViewController:viewController]) { 28 | NSParameterAssert([viewController conformsToProtocol:@protocol(MDImageContainerViewControllerDelegate)]); 29 | 30 | __block __weak id weak_self = self; 31 | self.translation = CGRectGetWidth([[viewController view] bounds]) / 3.; 32 | self.begin = ^(id interactiveTransition){ 33 | [viewController dismissViewControllerAnimated:YES completion:nil]; 34 | }; 35 | self.allowSwipe = ^CGFloat(CGPoint location, CGPoint velocity) { 36 | return [[viewController scrollView] zoomScale] <= [[viewController scrollView] minimumZoomScale] && velocity.y > 0; 37 | }; 38 | self.progress = ^CGFloat(CGPoint location, CGPoint translation, CGPoint velocity) { 39 | CGFloat distance = sqrt(pow(translation.x, 2) + pow(translation.y, 2)); 40 | return distance / [weak_self translation]; 41 | }; 42 | } 43 | return self; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /ImagePreview/MDImageDraggingDismissInteractionController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDImageDraggingDismissInteractionController : MDSwipeInteractionController 24 | 25 | // The max distance of dragging translation, default is controller.view.width / 3.f. 26 | @property (nonatomic, assign) CGFloat translation; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ImagePreview/MDImageDraggingDismissInteractionController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDImageDraggingDismissInteractionController.h" 22 | #import "MDImageZoomAnimationController.h" 23 | 24 | @interface MDImageDraggingDismissInteractionController () 25 | 26 | @property (nonatomic, weak, readonly) UIViewController *viewController; 27 | 28 | @property (nonatomic, strong, readonly) UIPanGestureRecognizer *panGestureRecognizer; 29 | 30 | @property (nonatomic, assign) BOOL interactionInProgress; 31 | 32 | @end 33 | 34 | @implementation MDImageDraggingDismissInteractionController 35 | @dynamic interactiveTransition, interactionInProgress, viewController, panGestureRecognizer; 36 | 37 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 38 | if (self = [super initWithViewController:viewController]) { 39 | NSParameterAssert([viewController conformsToProtocol:@protocol(MDImageContainerViewControllerDelegate)]); 40 | self.translation = CGRectGetWidth([[viewController view] bounds]) / 3.; 41 | } 42 | return self; 43 | } 44 | 45 | #pragma mark - UIPanGestureRecognizer handlers 46 | 47 | - (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)recognizer { 48 | CGPoint translation = [recognizer translationInView:[[self viewController] view]]; 49 | 50 | if ([recognizer state] == UIGestureRecognizerStateBegan) { 51 | self.interactionInProgress = YES; 52 | } else if ([recognizer state] == UIGestureRecognizerStateChanged) { 53 | CGFloat progress = sqrt(pow(translation.x, 2) + pow(translation.y, 2)) / [self translation]; 54 | progress = MIN(1.0, MAX(0.0, progress)); 55 | self.viewController.imageView.transform = CGAffineTransformIdentity; 56 | self.viewController.imageView.transform = CGAffineTransformScale(CGAffineTransformTranslate(CGAffineTransformIdentity, translation.x, translation.y), 1 - progress / 2., 1 - progress / 2.); 57 | self.viewController.backgroundView.alpha = (1 - progress); 58 | } else if ([recognizer state] == UIGestureRecognizerStateEnded || [recognizer state] == UIGestureRecognizerStateCancelled) { 59 | CGFloat progress = sqrt(pow(translation.x, 2) + pow(translation.y, 2)) / [self translation]; 60 | progress = MIN(1.0, MAX(0.0, progress)); 61 | // Finish or cancel the interactive transition 62 | if (progress > 0.5) { 63 | [[self viewController] dismissViewControllerAnimated:YES completion:nil]; 64 | } else { 65 | [UIView animateWithDuration:0.2 animations:^{ 66 | self.viewController.backgroundView.alpha = 1.f; 67 | self.viewController.imageView.transform = CGAffineTransformIdentity; 68 | }]; 69 | } 70 | self.interactionInProgress = NO; 71 | } 72 | } 73 | 74 | #pragma mark - UIGestureRecognizerDelegate 75 | 76 | - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)recognizer { 77 | UIScrollView *scrollView = [[self viewController] scrollView]; 78 | 79 | return recognizer == [self panGestureRecognizer] && [scrollView zoomScale] <= [scrollView minimumZoomScale]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /ImagePreview/MDImageViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDImageZoomAnimationController.h" 22 | 23 | // Simple full screen image viewer. 24 | // 25 | // Allows the user to view an image in full screen and double tap to zoom it. 26 | // The view controller can be dismissed with a single tap. 27 | @interface MDImageViewController : UIViewController 28 | 29 | // The background view. 30 | @property (nonatomic, strong, readonly) IBOutlet UIView *backgroundView; 31 | 32 | // The scroll view used for zooming. 33 | @property (nonatomic, strong, readonly) IBOutlet UIScrollView *scrollView; 34 | 35 | // The image view that displays the image. 36 | @property (nonatomic, strong, readonly) IBOutlet UIImageView *imageView; 37 | 38 | // The image that will be shown. 39 | @property (nonatomic, strong, readonly) UIImage *image; 40 | 41 | // The imageURL that will be downloaded and shown. 42 | @property (nonatomic, copy, readonly) NSURL *imageURL; 43 | 44 | // Initializes the receiver with the specified image. 45 | - (instancetype)initWithImage:(UIImage *)image; 46 | 47 | // Initializes the receiver with the specified image URL and placeholder. 48 | - (instancetype)initWithImageURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /ImagePreview/MDImageViewController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDImageViewController.h" 23 | #import "MDImageDismissInteractionController.h" 24 | #import "MDImageDraggingDismissInteractionController.h" 25 | 26 | @interface MDImageViewController () 27 | 28 | @property (nonatomic, strong) IBOutlet UIView *backgroundView; 29 | 30 | @property (nonatomic, strong) IBOutlet UIScrollView *scrollView; 31 | 32 | @property (nonatomic, strong) IBOutlet UIImageView *imageView; 33 | 34 | @property (nonatomic, strong) IBOutlet UITapGestureRecognizer *singleTapGestureRecognizer; 35 | 36 | @property (nonatomic, strong) IBOutlet UITapGestureRecognizer *doubleTapGestureRecognizer; 37 | 38 | @property (nonatomic, strong) UIImage *image; 39 | 40 | @property (nonatomic, copy) NSURL *imageURL; 41 | 42 | @end 43 | 44 | @implementation MDImageViewController 45 | 46 | - (instancetype)initWithImage:(UIImage *)image;{ 47 | return [self initWithImageURL:nil placeholderImage:image]; 48 | } 49 | 50 | - (instancetype)initWithImageURL:(NSURL *)imageURL placeholderImage:(UIImage *)placeholderImage;{ 51 | if (self = [super init]) { 52 | self.imageURL = imageURL; 53 | self.image = placeholderImage; 54 | self.modalPresentationStyle = UIModalPresentationCustom; 55 | } 56 | return self; 57 | } 58 | 59 | - (void)loadView{ 60 | [super loadView]; 61 | 62 | self.view.backgroundColor = [UIColor clearColor]; 63 | self.scrollView.contentSize = self.view.bounds.size; 64 | 65 | [[self view] addSubview:[self backgroundView]]; 66 | [[self view] addSubview:[self scrollView]]; 67 | [[self scrollView] addSubview:[self imageView]]; 68 | 69 | [[self imageView] addGestureRecognizer:[self singleTapGestureRecognizer]]; 70 | [[self imageView] addGestureRecognizer:[self doubleTapGestureRecognizer]]; 71 | } 72 | 73 | - (void)viewDidLoad { 74 | [super viewDidLoad]; 75 | 76 | // self.presentionInteractionController = [MDImageDismissInteractionController interactionControllerWithViewController:self]; 77 | MDImageDraggingDismissInteractionController *interactionController = [MDImageDraggingDismissInteractionController interactionControllerWithViewController:self]; 78 | interactionController.translation = 200.f; 79 | 80 | self.presentionInteractionController = interactionController; 81 | 82 | [[self singleTapGestureRecognizer] requireGestureRecognizerToFail:[self doubleTapGestureRecognizer]]; 83 | } 84 | 85 | #pragma mark - accessor 86 | 87 | - (UIView *)backgroundView{ 88 | if (!_backgroundView) { 89 | _backgroundView = [[UIView alloc] initWithFrame:[[self view] bounds]]; 90 | _backgroundView.backgroundColor = [UIColor blackColor]; 91 | } 92 | return _backgroundView; 93 | } 94 | 95 | - (UIScrollView *)scrollView{ 96 | if (!_scrollView) { 97 | _scrollView = [[UIScrollView alloc] initWithFrame:[[self view] bounds]]; 98 | _scrollView.delegate = self; 99 | _scrollView.maximumZoomScale = 2; 100 | } 101 | return _scrollView; 102 | } 103 | 104 | - (UIImageView *)imageView{ 105 | if (!_imageView) { 106 | _imageView = [[UIImageView alloc] initWithFrame:[[self view] bounds]]; 107 | _imageView.image = [self image]; 108 | _imageView.userInteractionEnabled = YES; 109 | _imageView.multipleTouchEnabled = YES; 110 | _imageView.contentMode = UIViewContentModeScaleAspectFit; 111 | 112 | if ([self imageURL]) { 113 | _imageView.image = [UIImage imageWithContentsOfFile:[[self imageURL] absoluteString]]; 114 | } 115 | } 116 | return _imageView; 117 | } 118 | 119 | - (UITapGestureRecognizer *)singleTapGestureRecognizer{ 120 | if (!_singleTapGestureRecognizer) { 121 | _singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; 122 | _singleTapGestureRecognizer.numberOfTapsRequired = 1; 123 | } 124 | return _singleTapGestureRecognizer; 125 | } 126 | 127 | - (UITapGestureRecognizer *)doubleTapGestureRecognizer{ 128 | if (!_doubleTapGestureRecognizer) { 129 | _doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; 130 | _doubleTapGestureRecognizer.numberOfTapsRequired = 2; 131 | } 132 | return _doubleTapGestureRecognizer; 133 | } 134 | 135 | #pragma mark - UIScrollViewDelegate 136 | 137 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { 138 | return [self imageView]; 139 | } 140 | 141 | #pragma mark - MDPresentionController 142 | 143 | - (id)animationForPresentionOperation:(MDPresentionAnimatedOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 144 | return [MDImageZoomAnimationController animationForPresentOperation:operation fromViewController:fromViewController toViewController:toViewController]; 145 | } 146 | 147 | #pragma mark - actions 148 | 149 | - (IBAction)handleSingleTap:(UITapGestureRecognizer *)tapGestureRecognizer { 150 | [self dismissViewControllerAnimated:YES completion:nil]; 151 | } 152 | 153 | - (IBAction)handleDoubleTap:(UITapGestureRecognizer *)tapGestureRecognizer { 154 | if ([[self scrollView] zoomScale] == [[self scrollView] minimumZoomScale]) { 155 | // Zoom in 156 | CGPoint center = [tapGestureRecognizer locationInView:[self scrollView]]; 157 | CGSize size = CGSizeMake(self.scrollView.bounds.size.width / self.scrollView.maximumZoomScale, 158 | self.scrollView.bounds.size.height / self.scrollView.maximumZoomScale); 159 | CGRect rect = CGRectMake(center.x - (size.width / 2.0), center.y - (size.height / 2.0), size.width, size.height); 160 | [[self scrollView] zoomToRect:rect animated:YES]; 161 | } else { 162 | // Zoom out 163 | [[self scrollView] zoomToRect:[[self scrollView] bounds] animated:YES]; 164 | } 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /ImagePreview/MDImageZoomAnimationController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | // Image zoom custom transition. 24 | @interface MDImageZoomAnimationController : NSObject 25 | 26 | // The image view that will be used as the source (zoom in) or destination 27 | // (zoom out) of the transition. 28 | @property (nonatomic, weak, readonly) UIImageView *referenceImageView; 29 | 30 | @property (nonatomic, assign) BOOL hideReferenceImageViewWhenZoomIn; // Default is YES. 31 | 32 | // Initializes the receiver with the specified reference image view to other image view. 33 | - (instancetype)initWithReferenceImageView:(UIImageView *)referenceImageView; 34 | 35 | @end 36 | 37 | // Support MPresentionAnimatedTransitioning 38 | @protocol MDImageZoomViewControllerDelegate 39 | 40 | @property (nonatomic, weak, readonly) UIImageView *imageView; 41 | 42 | @end 43 | 44 | @protocol MDImageContainerViewControllerDelegate 45 | 46 | @property (nonatomic, weak, readonly) UIView *backgroundView; 47 | @property (nonatomic, weak, readonly) UIScrollView *scrollView; 48 | 49 | @end 50 | 51 | @interface MDImageZoomAnimationController (MPresentionAnimatedTransitioning) 52 | 53 | + (id)animationForPresentOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 54 | 55 | - (instancetype)initWithPresentionAnimatedOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /ImagePreview/MDImageZoomAnimationController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDImageZoomAnimationController.h" 22 | 23 | CGRect MDImageZoomAnimationControllerAspectFitRectForSize(UIImage *image, CGSize size){ 24 | CGFloat targetAspect = size.width / size.height; 25 | CGFloat sourceAspect = image.size.width / image.size.height; 26 | CGRect rect = CGRectZero; 27 | 28 | if (targetAspect > sourceAspect) { 29 | rect.size.height = size.height; 30 | rect.size.width = ceilf(rect.size.height * sourceAspect); 31 | rect.origin.x = ceilf((size.width - rect.size.width) * 0.5); 32 | } 33 | else { 34 | rect.size.width = size.width; 35 | rect.size.height = ceilf(rect.size.width / sourceAspect); 36 | rect.origin.y = ceilf((size.height - rect.size.height) * 0.5); 37 | } 38 | 39 | return rect; 40 | } 41 | 42 | @interface MDImageZoomAnimationController () 43 | 44 | @property (nonatomic, assign) NSTimeInterval duration; 45 | 46 | @property (nonatomic, assign) MDPresentionAnimatedOperation presentionAnimatedOperation; 47 | 48 | @property (nonatomic, weak) UIViewController *fromViewController; 49 | @property (nonatomic, weak) UIViewController *toViewController; 50 | 51 | @end 52 | 53 | @implementation MDImageZoomAnimationController 54 | 55 | - (instancetype)initWithReferenceImageView:(UIImageView *)referenceImageView;{ 56 | if (self = [super init]) { 57 | NSAssert([referenceImageView contentMode] == UIViewContentModeScaleAspectFill, @"*** referenceImageView must have a UIViewContentModeScaleAspectFill contentMode!"); 58 | _referenceImageView = referenceImageView; 59 | _hideReferenceImageViewWhenZoomIn = YES; 60 | } 61 | return self; 62 | } 63 | 64 | - (NSTimeInterval)transitionDuration:(id)transitioning { 65 | UIViewController *viewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 66 | return [viewController isBeingPresented] ? 0.5 : 0.25; 67 | } 68 | 69 | - (void)animateTransition:(id)transitioning { 70 | if ([self presentionAnimatedOperation] == MDPresentionAnimatedOperationPresent) { 71 | [self zoomInTransitioning:transitioning]; 72 | } else if ([self presentionAnimatedOperation] == MDPresentionAnimatedOperationDismiss) { 73 | [self zoomOutTransitioning:transitioning]; 74 | } 75 | } 76 | 77 | - (void)zoomInTransitioning:(id)transitioning { 78 | // Get the view controllers participating in the transition 79 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 80 | UIViewController *toViewController = (id)[transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 81 | NSAssert([toViewController conformsToProtocol:@protocol(MDImageZoomViewControllerDelegate)], @"*** toViewController must conforms to protocol for YRImageViewController!"); 82 | 83 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 84 | 85 | UIView *containerView = [transitioning containerView]; 86 | UIColor *windowBackgroundColor = [window backgroundColor]; 87 | 88 | window.backgroundColor = [UIColor blackColor]; 89 | // Create a temporary view for the zoom in transition and set the initial frame based 90 | // on the reference image view 91 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[[self referenceImageView] image]]; 92 | imageView.contentMode = UIViewContentModeScaleAspectFill; 93 | imageView.clipsToBounds = YES; 94 | imageView.frame = [containerView convertRect:[[self referenceImageView] bounds] fromView:[self referenceImageView]]; 95 | [containerView addSubview:imageView]; 96 | [containerView sendSubviewToBack:[fromViewController view]]; 97 | 98 | // Compute the final frame for the temporary view 99 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 100 | CGRect transitionViewFinalFrame = MDImageZoomAnimationControllerAspectFitRectForSize([[self referenceImageView] image], finalFrame.size); 101 | 102 | if ([self hideReferenceImageViewWhenZoomIn]) { 103 | self.referenceImageView.hidden = YES; 104 | } 105 | // Perform the transition using a spring motion effect 106 | NSTimeInterval duration = [self transitionDuration:transitioning]; 107 | 108 | [UIView animateWithDuration:duration 109 | delay:0 110 | usingSpringWithDamping:0.7 111 | initialSpringVelocity:0 112 | options:UIViewAnimationOptionCurveLinear 113 | animations:^{ 114 | fromViewController.view.alpha = 0; 115 | imageView.frame = transitionViewFinalFrame; 116 | } 117 | completion:^(BOOL finished) { 118 | window.backgroundColor = windowBackgroundColor; 119 | fromViewController.view.alpha = 1; 120 | 121 | if ([transitioning transitionWasCancelled] && [self hideReferenceImageViewWhenZoomIn]) { 122 | self.referenceImageView.hidden = NO; 123 | } 124 | 125 | [imageView removeFromSuperview]; 126 | 127 | if (![transitioning transitionWasCancelled]) { 128 | [containerView addSubview:[toViewController view]]; 129 | } 130 | 131 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 132 | }]; 133 | } 134 | 135 | - (void)zoomOutTransitioning:(id)transitioning { 136 | // Get the view controllers participating in the transition 137 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 138 | UIViewController *fromViewController = (id)[transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 139 | NSAssert([fromViewController conformsToProtocol:@protocol(MDImageZoomViewControllerDelegate)], @"*** fromViewController must conforms to protocol for YRImageViewController!"); 140 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 141 | 142 | UIView *containerView = [transitioning containerView]; 143 | UIColor *windowBackgroundColor = [window backgroundColor]; 144 | 145 | // The toViewController view will fade in during the transition 146 | toViewController.view.frame = [transitioning finalFrameForViewController:toViewController]; 147 | 148 | if ([fromViewController modalPresentationStyle] == UIModalPresentationNone) { 149 | toViewController.view.alpha = 0; 150 | window.backgroundColor = [UIColor blackColor]; 151 | 152 | [containerView addSubview:[toViewController view]]; 153 | [containerView sendSubviewToBack:[toViewController view]]; 154 | } 155 | // Compute the initial frame for the temporary view based on the image view 156 | // of the YRImageViewController 157 | UIImageView *referenceImageView = [self referenceImageView]; 158 | UIImageView *fromReferenceImageView = [fromViewController imageView]; 159 | CGRect transitionViewInitialFrame = MDImageZoomAnimationControllerAspectFitRectForSize([fromReferenceImageView image], [fromReferenceImageView bounds].size); 160 | transitionViewInitialFrame = [containerView convertRect:transitionViewInitialFrame fromView:fromReferenceImageView]; 161 | 162 | // Compute the final frame for the temporary view based on the reference 163 | // image view 164 | CGRect transitionViewFinalFrame = [containerView convertRect:[referenceImageView bounds] fromView:referenceImageView]; 165 | 166 | // Create a temporary view for the zoom out transition based on the image 167 | // view controller contents 168 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[fromReferenceImageView image]]; 169 | imageView.contentMode = UIViewContentModeScaleAspectFill; 170 | imageView.layer.cornerRadius = [[referenceImageView layer] cornerRadius]; 171 | imageView.layer.borderWidth = [[referenceImageView layer] borderWidth]; 172 | imageView.layer.borderColor = [[referenceImageView layer] borderColor]; 173 | imageView.clipsToBounds = YES; 174 | imageView.frame = transitionViewInitialFrame; 175 | 176 | [containerView addSubview:imageView]; 177 | 178 | fromReferenceImageView.hidden = YES; 179 | if ([self hideReferenceImageViewWhenZoomIn]) { 180 | referenceImageView.hidden = YES; 181 | } 182 | // Perform the transition 183 | NSTimeInterval duration = [self transitionDuration:transitioning]; 184 | 185 | [UIView animateWithDuration:duration 186 | delay:0 187 | options:UIViewAnimationOptionCurveEaseInOut 188 | animations:^{ 189 | toViewController.view.alpha = 1.f; 190 | fromViewController.view.alpha = 0.f; 191 | imageView.frame = transitionViewFinalFrame; 192 | } completion:^(BOOL finished) { 193 | if ([self hideReferenceImageViewWhenZoomIn]) { 194 | referenceImageView.hidden = NO; 195 | } 196 | window.backgroundColor = windowBackgroundColor; 197 | [imageView removeFromSuperview]; 198 | 199 | if ([transitioning transitionWasCancelled]) { 200 | fromReferenceImageView.hidden = NO; 201 | fromViewController.view.alpha = 1.f; 202 | [[toViewController view] removeFromSuperview]; 203 | } 204 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 205 | }]; 206 | } 207 | 208 | @end 209 | 210 | @implementation MDImageZoomAnimationController (MPresentionAnimatedTransitioning) 211 | 212 | + (id)animationForPresentOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 213 | return [[self alloc] initWithPresentionAnimatedOperation:presentionAnimatedOperation fromViewController:fromViewController toViewController:toViewController]; 214 | } 215 | 216 | - (instancetype)initWithPresentionAnimatedOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 217 | 218 | NSParameterAssert(presentionAnimatedOperation != MDPresentionAnimatedOperationNone); 219 | NSParameterAssert([fromViewController respondsToSelector:@selector(imageView)]); 220 | NSParameterAssert([toViewController respondsToSelector:@selector(imageView)]); 221 | 222 | UIImageView *referenceImageView = presentionAnimatedOperation == MDPresentionAnimatedOperationPresent ? [fromViewController imageView] : [toViewController imageView]; 223 | if (self = [self initWithReferenceImageView:referenceImageView]) { 224 | self.presentionAnimatedOperation = presentionAnimatedOperation; 225 | self.fromViewController = fromViewController; 226 | self.toViewController = toViewController; 227 | self.hideReferenceImageViewWhenZoomIn = YES; 228 | } 229 | return self; 230 | } 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /ImagePreview/MDTransitioning+ImagePreview.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | //! Project version number for MDTransitioning. 22 | FOUNDATION_EXPORT double MDTransitioning_ImagePreviewVersionNumber; 23 | 24 | //! Project version string for MDTransitioning. 25 | FOUNDATION_EXPORT const unsigned char MDTransitioning_ImagePreviewVersionString[]; 26 | 27 | // In this header, you should import all the public headers of your framework using statements like #import 28 | 29 | #import 30 | #import 31 | #import 32 | #import 33 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Modool 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MDTransitioning.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## MDTransitioning 4 | @copyright Modool 5 | 6 | ### 前言 7 | 8 | 转场动画就是以某种方式从一个场景以动画的形式过渡到另一个场景。 9 | 10 | 然而,动画的可变性太强,每个设计师都有自己的想法,对于开发来说,是无法用固定的模式来限制动画的实现。 11 | 其次,系统已经为我们提供了一套很好的动画模板,我们只需要实现其相关方法,就能够很容易的实现各种各样的动画。 12 | 13 | 所以,本文将要介绍的并不是转场所需要的动画,而是针对"转场过程控制"的一种设计方案,以便提供一种具有可定制,可扩展的设计方案。 14 | 15 | 为了方便集成,我们也提供了很多套可选的动画方案,比如传统的侧滑、缩放、图片预览等等。 16 | 17 | ###iOS7 以前 18 | 19 | 在 iOS7 以前,系统不支持手势右划返回的,只能实现一些过度动画,如以下方案: 20 | 21 | ``` 22 | // Code here 23 | // Custom present 24 | [toViewController willMoveToParentViewController:self]; 25 | [fromViewController willMoveToParentViewController:nil]; 26 | 27 | [self addChildViewController:toViewController]; 28 | [[self view] addSubview:[toViewController view]]; 29 | 30 | [self transitionFromViewController:fromViewController 31 | toViewController:toViewController 32 | duration:0.3 33 | options:UIViewAnimationOptionTransitionCrossDissolve 34 | animations:^{ 35 | // 过度效果 36 | } 37 | completion:^(BOOL finished) { 38 | [fromViewController removeFromSuperView]; 39 | [fromViewController removeFromParentViewController]; 40 | [fromViewController didMoveToParentViewController:nil]; 41 | [toViewController didMoveToParentViewController:self]; 42 | }]; 43 | ``` 44 | 或者 45 | 46 | ``` 47 | // Code here 48 | [navigationController pushViewController:toViewController animated:NO]; 49 | [UIView animateWithDuration:0.3 50 | options:UIViewAnimationOptionTransitionCrossDissolve 51 | animations:^{ 52 | // 过度效果 53 | } 54 | completion:nil]; 55 | ``` 56 | iOS7以前,没有为`Controller` 提供 `transitioningDelegate` 57 | 58 | ``` 59 | // Code here 60 | @interface UIViewController(UIViewControllerTransitioning) 61 | 62 | @property (nullable, nonatomic, weak) id transitioningDelegate; 63 | 64 | @end 65 | 66 | ``` 67 | 所以对于`Present`、`Dismiss`来说,尚且还是可以实现,而对于`Push` 和 `Pop`的定制非常困难,就更不要说针对转场来进行交互控制。 68 | 69 | ###iOS7 以后 70 | 71 | 在 iOS7 以后,系统针对交互转场这方面出现了很大变化,不仅支持了手势交互,还提供了一套标准的转场协议和动画协议。 72 | 73 | ####默认交互方案 74 | 75 | 首先,我们来看下 `Push` 和 `Pop`,在我们不去实现任何交互,以及任何动画的时候,系统所提供给我们的交互方案: 76 | 77 | ``` 78 | // Code here 79 | @interface UINavigationController : UIViewController 80 | 81 | // 系统默认提供的侧滑手势(从屏幕边界往右划) 82 | @property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer 83 | 84 | @end 85 | 86 | ``` 87 | 我们看到,系统默认的手势是基于`UINavigationController`的,也就是说,手势是加在 `UINavigationController` 的 transitionView 上的,而且是只读的,我们无法篡改手势,以及无法定制手势,当然,这其中其他的问题,我们待会再说。 88 | 89 | 我们继续再看下系统默认的`Push`和`Pop`转场定制方案: 90 | 91 | #####默认转场方案 92 | 93 | * `UIViewControllerInteractiveTransitioning` 94 | 转场协议:虽然说是控制转场交互的,但是并没有达到字面意思上所具备动能。 95 | 96 | * `UIPercentDrivenInteractiveTransition` 97 | 转场进度控制器:系统默认提供的,通过百分比来控制转场的播放进度。 98 | 99 | ``` 100 | // Code here 101 | // UINavigationControllerDelegate 102 | // 如果需要定制转场控制方案,需提供UIViewControllerInteractiveTransitioning实例, 103 | // 默认情况下不需要实现此代理, 104 | 105 | - (id)navigationController:(UINavigationController *)navigationController 106 | interactionControllerForAnimationController:(MDNavigationAnimationController *)animationController { 107 | return [UIPercentDrivenInteractiveTransition new]; 108 | } 109 | 110 | ``` 111 | ###默认动画方案 112 | 113 | * `UIViewControllerAnimatedTransitioning` 114 | 动画协议:当`Push`或者`Pop`动作发生后,会通过代理获取到该协议的具体动画实例。 115 | 116 | ``` 117 | // Code here 118 | // UINavigationControllerDelegate 119 | // 如果需要定制动画方案,需提供UIViewControllerAnimatedTransitioning实例, 120 | // 默认情况下不需要实现此代理, 121 | 122 | - (id)navigationController:(UINavigationController *)navigationController 123 | animationControllerForOperation:(UINavigationControllerOperation)operation 124 | fromViewController:(UIViewController *)fromViewController 125 | toViewController:(UIViewController *)toViewController { 126 | if (operation == UINavigationControllerOperationPush) return push animation; 127 | if (operation == UINavigationControllerOperationPop) return pop animation; 128 | return nil; 129 | } 130 | ``` 131 | 132 | 我再来看下`Present`、`Dismiss`,和`Push`、`Pop`类似 133 | 134 | ``` 135 | // Code here 136 | - (id)animationControllerForPresentedController:(MDImageViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 137 | return present transitioning; 138 | } 139 | - (id)animationControllerForDismissedController:(MDImageViewController *)dismissed { 140 | return dismiss transitioning; 141 | } 142 | - (id)interactionControllerForPresentation:(id )animator;{ 143 | return present interactive transitioning; 144 | } 145 | - (id)interactionControllerForDismissal:(id)animator;{ 146 | return dismiss interactive transitioning; 147 | } 148 | 149 | ``` 150 | 无论是`Present`、`Dismiss`、`Push`、`Pop`中的哪一种,都要遵从下面这个流程 151 | 152 | 153 | 由于基于系统的默认方案,我们会有以下三个问题: 154 | 155 | * 可以针对每个Controller定制动画,但是由于`UINavigationController`,`interactivePopGestureRecognizer`以及`transitioningDelegate`的局限性,在维护上相对离散,没有一个统一的方案; 156 | * 不可以针对每个Controller定制交互 157 | * 不可以针对每个Controller转场控制的 158 | * 对第三方动画和交互控制器的集成相对复杂 159 | 160 | ###所有我们准备提供一套完整的可扩展方案来解决这几个问题 161 | 162 | ### Why `MDTransitioning`? 163 | 164 | 基于上面的流程图来看,倘若我们需要针对每个转场进行定制,工作相对繁琐,维护困难。 165 | 所以`MDTransitioning`方案基于以下几个原则: 166 | 167 | * 交互:从谁那里来,就由谁提供 168 | * 动画:到哪里去,就由谁提供 169 | * 控制:谁触发,就由谁维护 170 | 171 | ###类关系 172 | 173 | ###动画类 174 | 175 | 176 | * MDViewControllerAnimatedTransitioning 177 | 178 | 基于`UIViewControllerAnimatedTransitioning`协议的再次封装,对关联的主从`View Controller`进行定义 179 | 180 | * `MDNavigationAnimatedTransitioning` 181 | 基于`MDViewControllerAnimatedTransitioning`协议的再次封装,定义`Push`和`Pop`的两种动画方式 182 | 183 | * `MDNavigationAnimationController` 184 | 基于`MDNavigationAnimatedTransitioning`协议的默认实现,默认实现`Push`和`Pop`动画,呈现方式和系统保持一致 185 | 186 | * `MPresentionAnimatedTransitioning` 187 | 基于`MDViewControllerAnimatedTransitioning`协议的再次封装,定义`Present`和`Dismiss`的两种动画方式 188 | 189 | * `MDPresentionAnimationController` 190 | 基于`MPresentionAnimatedTransitioning `协议的默认实现,默认实现`Present `和`Dismiss `动画,呈现方式和系统保持一致 191 | 192 | ###交互驱动类 193 | 194 | * `MDPercentDrivenInteractiveTransitioning` 195 | 基于系统UIViewControllerInteractiveTransitioning协议的再次封装,定义驱动所需的常规方法 196 | 197 | * `UIPercentDrivenInteractiveTransition` 198 | 系统提供的默认百分比驱动器,以便后期对驱动的扩展 199 | 200 | ###交互控制类 201 | 202 | * `MDInteractionController` 203 | 交互控制协议,负责控制交互的生命周期,手势变化,以及转场触发和进度维护 204 | 205 | * `MDSwipeInteractionController` 206 | 基于`MDInteractionController`协议的实现,实现对滑动手势交互的控制 207 | 208 | * `MDPopInteractionController` 209 | 基于`MDSwipeInteractionController`,提供`Pop`动作的滑动条件,以及进度计算 210 | 211 | * `` 212 | `Pop`动作控制器,默认由`UIViewController`实现,负责控制交互的加载条件、初始化、以及手势依赖的`UIView` 213 | 214 | * `` 215 | `Present`、`Dismiss`动作控制器,默认由`UIViewController`实现,负责控制Presention交互的加载条件、初始化、以及手势依赖的`UIView` 216 | 217 | ###优点 218 | 219 | * 提供一套默认的方案,和系统效果保持一致 220 | * 提供所有定制方案的底层类,轻轻松松就能完成自定义交互和动画的集成 221 | * 方便集成第三方动画和交互控制器,例如CE系列 222 | * 重点在这里,默认方案,**零写入**,**零入侵** 223 | 224 | ###到底有多简单? 225 | 226 | **** 227 | 228 | ### 案例一 229 | 230 | * `MDNavigationControllerDelegate ` 231 | 为了方便接入,我们提供了默认的`Pop`和`Push`代理实现,只需要下面一行代码,就可以实现对系统转场的替换。 232 | 233 | ``` 234 | // Code here 235 | navigationController.delegate = [MDNavigationControllerDelegate defaultDelegate]; 236 | 237 | ``` 238 | 效果和系统的保持一致 239 | 240 | 241 | 242 | 243 | 244 | 245 | ### 案例二 246 | 247 | * `MDPresentionControllerDelegate ` 248 | 当然对于`Present`和`Dismiss`我们也提供了默认的代理实现,同样只需要下面一行代码对系统转场的替换。 249 | 250 | ``` 251 | // Code here 252 | viewController.transitioningDelegate = [MDPresentionControllerDelegate delegateWithReferenceViewController:referenceViewController]; 253 | 254 | ``` 255 | 效果和系统的保持一致 256 | 257 | 258 | 259 | 260 | ### 为某个`View Contorller`定制一个缩放的`Pop`动画,但`Push`动画用默认的 261 | 262 | ``` 263 | // Code here 264 | // 在将要显示的`View Contorller`内实现该方法,默认实现返回父类结果 265 | - (id)animationForNavigationOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 266 | if (operation == UINavigationControllerOperationPush) { 267 | return [super animationForNavigationOperation:operation fromViewController:fromViewController toViewController:toViewController]; 268 | } else { 269 | return [[MDScaleNavigationAnimationController alloc] initWithOperation:operation fromViewController:fromViewController toViewController:toViewController]; 270 | } 271 | } 272 | 273 | ``` 274 | 275 | ### 案例三 276 | ### 因为水平pop是默认实现的,所以我们调整一下,为某个`View Contorller`定制一个垂直滑动的`Pop`手势交互,虽然有点变态,但是这仅为测试 277 | 278 | ``` 279 | // Code here 280 | // 在将要显示的`View Contorller`中复写该方法,提供垂直滑动的交互控制器 281 | - (id)requirePopInteractionController{ 282 | return [MDVerticalSwipPopInteractionController interactionControllerWithViewController:self]; 283 | } 284 | 285 | ``` 286 | 效果如图: 287 | 288 | 289 | 290 | ### 案例四 291 | 292 | #### 为某个`View Contorller`定制一个图片放大的`Present`动画,但`Dismiss`动画用默认抽屉式的 293 | 294 | ``` 295 | // Code here 296 | // 在将要显示的`View Contorller`内实现该方法,默认实现返回父类结果 297 | - (id)animationForPresentionOperation:(MDPresentionAnimatedOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 298 | if (operation == MDPresentionAnimatedOperationPresent) { 299 | MDImageZoomAnimationController *controller = [MDImageZoomAnimationController animationForPresentOperation:operation fromViewController:fromViewController toViewController:toViewController]; 300 | controller.hideReferenceImageViewWhenZoomIn = NO; 301 | return controller; 302 | } else { 303 | return [[MDPresentionAnimationController alloc] initWithOperation:operation fromViewController:fromViewController toViewController:toViewController]; 304 | } 305 | } 306 | 307 | ``` 308 | ### 案例五 309 | 310 | ### 图片预览器,为某个`View Contorller`定制一个图片缩小的`Dismiss`手势交互 311 | 312 | ``` 313 | // Code here 314 | // 在将要显示的`View Contorller`的`viewDidLoad`方法中添加交互控制器 315 | - (void)viewDidLoad { 316 | [super viewDidLoad]; 317 | 318 | MDImageDraggingDismissInteractionController *interactionController = [MDImageDraggingDismissInteractionController interactionControllerWithViewController:self]; 319 | interactionController.translation = 200.f; 320 | 321 | self.presentionInteractionController = interactionController; 322 | } 323 | 324 | ``` 325 | 326 | 效果如图: 327 | 328 | 329 | 330 | ### 现成的动画和交互太少怎么办? 331 | 332 | 配合CE系列的动画和交互一起使用,我们提供CE的扩展方案MDTransitioning-VCTransitionsLibrary. 333 | 334 | 335 | ## 联系方式 336 | 337 | -------------------------------------------------------------------------------- /MDTransitioning.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MDTransitioning.xcodeproj/xcshareddata/xcschemes/MDTransitioning.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /MDTransitioning.xcodeproj/xcshareddata/xcschemes/MDTransitioning_ImagePriview.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /MDTransitioning.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /MDTransitioning.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MDTransitioning/MDAnimatedTransitioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @protocol MDInteractionController; 24 | 25 | // This is baseic protocol of animated transitioning, extend to access view controllers in transition view. 26 | @protocol MDViewControllerAnimatedTransitioning 27 | 28 | // The duration of animation. 29 | @property (nonatomic, assign) NSTimeInterval duration; 30 | 31 | // Access appearing view controller in transition view. 32 | @property (nonatomic, weak, readonly) UIViewController *fromViewController; 33 | 34 | // Access view controller will be appearing in transition view. 35 | @property (nonatomic, weak, readonly) UIViewController *toViewController; 36 | 37 | @end 38 | 39 | // This is navigation transitioning protocol, extend to access operation. 40 | @protocol MDNavigationAnimatedTransitioning 41 | 42 | // Access operation, push or pop. 43 | @property (nonatomic, assign, readonly) UINavigationControllerOperation navigationControllerOperation; 44 | 45 | /** 46 | The designated initializer. If you subclass MDNavigationAnimationController, you must call the super implementation of this 47 | method. 48 | 49 | @param navigationControllerOperation navigation controller operation, push or pop. 50 | @param fromViewController view controller appearing. 51 | @param toViewController view controller will be appearing. 52 | @return an instance of MDNavigationAnimationController or sub class. 53 | */ 54 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)navigationControllerOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 55 | 56 | @end 57 | 58 | // Enum of presention operations, present and dismiss. 59 | typedef NS_ENUM(NSInteger, MDPresentionAnimatedOperation) { 60 | MDPresentionAnimatedOperationNone, 61 | MDPresentionAnimatedOperationPresent, 62 | MDPresentionAnimatedOperationDismiss, 63 | }; 64 | 65 | // This is presention transitioning protocol, extend to access operation. 66 | @protocol MPresentionAnimatedTransitioning 67 | 68 | // Access operation, present or dismiss. 69 | @property (nonatomic, assign, readonly) MDPresentionAnimatedOperation presentionAnimatedOperation; 70 | 71 | /** 72 | The designated initializer. If you subclass MDNavigationAnimationController, you must call the super implementation of this 73 | method. 74 | 75 | @param presentionAnimatedOperation presention controller operation, present or dismiss. 76 | @param fromViewController view controller appearing. 77 | @param toViewController view controller will be appearing. 78 | @return an instance of MDPresentionAnimationController or sub class. 79 | */ 80 | - (instancetype)initWithPresentionAnimatedOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 81 | 82 | @end 83 | 84 | 85 | -------------------------------------------------------------------------------- /MDTransitioning/MDInteractionController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDAnimatedTransitioning.h" 22 | #import "MDInteractiveTransitioning.h" 23 | 24 | // This is interaction controller control, control interaction of gesture 25 | // and progress of interactive transition, the gesture will be added in view of view controller, 26 | // Needs to care conflict for gestures if overrides. 27 | @protocol MDInteractionController 28 | 29 | // The view controller with gesture. 30 | @property (nonatomic, weak, readonly) UIViewController *viewController; 31 | 32 | // The interactive transition, control progress animation. 33 | @property (nonatomic, strong, readonly) id interactiveTransition; 34 | 35 | // The current interaction state. 36 | @property (nonatomic, assign, readonly) BOOL interactionInProgress; 37 | 38 | // To control ability of gesture. 39 | @property (nonatomic, assign) BOOL enable; 40 | 41 | // To control ability of gesture dynamic. 42 | @property (nonatomic, copy) CGFloat (^allowSwipe)(CGPoint location, CGPoint velocity); 43 | 44 | // To provide progress with location, translation and velocity. 45 | @property (nonatomic, copy) CGFloat (^progress)(CGPoint location, CGPoint translation, CGPoint velocity); 46 | 47 | // It‘s called after begginning of gesture. 48 | @property (nonatomic, copy) void (^begin)(id interactiveTransition); // Default is called requireInteractiveTransition. 49 | 50 | // It‘s called after end of gesture. 51 | @property (nonatomic, copy) void (^end)(id interactiveTransition, BOOL finished); 52 | 53 | // It‘s called after updating progress of gesture. 54 | @property (nonatomic, copy) void (^update)(id interactiveTransition, CGFloat progress); 55 | 56 | /** 57 | Require an interactive transition base on percent driven. 58 | 59 | @return an instance base on protocol MDPercentDrivenInteractiveTransitioning, default is UIPercentDrivenInteractiveTransition. 60 | */ 61 | - (id)requireInteractiveTransition; 62 | 63 | + (instancetype)interactionControllerWithViewController:(UIViewController *)viewController; 64 | - (instancetype)initWithViewController:(UIViewController *)viewController; 65 | 66 | @end 67 | 68 | // This is navigation controller with pop interaction, contain an interaction controler 69 | // and animation provider. 70 | @protocol MDNavigationPopController 71 | 72 | // Snapshot is created before view controller is disappearing. 73 | @property (nonatomic, strong) UIView *snapshot; 74 | @property (nonatomic, strong) UIView *navigationBarSnapshot; 75 | 76 | // Interaction controller control both geture and transitioning progress. 77 | @property (nonatomic, strong) id interactionController; 78 | 79 | // The interaction controller is invalid if it's NO, default is YES. 80 | @property (nonatomic, assign) BOOL allowPopInteractive; 81 | 82 | // Needs to provide an interaction controller without inner control if it's YES, 83 | // and needs to control outside gesture, default is NO. 84 | @property (nonatomic, assign) BOOL allowCustomPopInteractive; 85 | 86 | /** 87 | Require an pop interaction controller. 88 | 89 | @return an instance base on protocol MDInteractionController, default is MDPopInteractionController. 90 | */ 91 | - (id)requirePopInteractionController; 92 | 93 | /** 94 | Provide an navigation transitioning, ignored push interaction. 95 | 96 | @param operation navigation controller operation, push or pop. 97 | @param fromViewController view controller appearing. 98 | @param toViewController view controller will be appearing. 99 | @return an instance of animated transitioning, default is MDNavigationAnimationController. 100 | */ 101 | - (id)animationForNavigationOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 102 | 103 | @end 104 | 105 | // This is presention controller with present or dismiss interaction, 106 | // also contain an interaction controler and animation provider. 107 | @protocol MDPresentionController 108 | 109 | // Interaction controller control both geture and transitioning progress. 110 | @property (nonatomic, strong) id presentionInteractionController; 111 | 112 | /** 113 | Provide an presention transitioning. 114 | 115 | @param operation presention controller operation, presnt or dismiss. 116 | @param fromViewController view controller appearing. 117 | @param toViewController view controller will be appearing. 118 | @return an instance of animated transitioning, default is MDPresentionAnimationController. 119 | */ 120 | - (id)animationForPresentionOperation:(MDPresentionAnimatedOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /MDTransitioning/MDInteractiveTransitioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | // This is baseic protocol of interactive transitioning, interactive progress base on percent. 24 | @protocol MDPercentDrivenInteractiveTransitioning 25 | 26 | // Duration of transitioning. 27 | @property (nonatomic, assign, readonly) CGFloat duration; 28 | 29 | // Current completed percent of transition. 30 | @property (nonatomic, assign, readonly) CGFloat percentComplete; 31 | 32 | // Pause playing transition. 33 | - (void)pauseInteractiveTransition NS_AVAILABLE_IOS(10_0); 34 | 35 | // Update progress of playing transition. 36 | - (void)updateInteractiveTransition:(CGFloat)percentComplete; 37 | 38 | // Cancel playing transition. 39 | - (void)cancelInteractiveTransition; 40 | 41 | // Finish playing transition. 42 | - (void)finishInteractiveTransition; 43 | 44 | @end 45 | 46 | // System interactive transition 47 | @interface UIPercentDrivenInteractiveTransition (MDPercentDrivenInteractiveTransitioning) 48 | @end 49 | -------------------------------------------------------------------------------- /MDTransitioning/MDNavigationAnimationController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDAnimatedTransitioning.h" 23 | 24 | // The default navigation animation controller base on MDNavigationAnimatedTransitioning 25 | @interface MDNavigationAnimationController : NSObject 26 | 27 | // The duration of animation, default is 0.25f. 28 | @property (nonatomic, assign) NSTimeInterval duration; 29 | 30 | // The duration of animation, default is 0.25f. 31 | @property (nonatomic, assign, getter=isSnapshotEnabled) BOOL snapshotEnable; 32 | 33 | /** 34 | The designated initializer. If you subclass MDNavigationAnimationController, you must call the super implementation of this 35 | method. 36 | 37 | @param navigationControllerOperation navigation controller operation, push or pop. 38 | @param fromViewController view controller appearing. 39 | @param toViewController view controller will be appearing. 40 | @return an instance of MDNavigationAnimationController or sub class. 41 | */ 42 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)navigationControllerOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 43 | 44 | - (instancetype)init DEPRECATED_MSG_ATTRIBUTE(" Use initWithOperation:fromViewController:toViewController: instead"); 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /MDTransitioning/MDNavigationAnimationController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDNavigationAnimationController.h" 22 | #import "MDPopInteractionController.h" 23 | #import "UIViewController+MDNavigationTransitioning.h" 24 | 25 | @interface MDNavigationAnimationController () 26 | 27 | @property (nonatomic, assign) UINavigationControllerOperation navigationControllerOperation; 28 | @property (nonatomic, weak) UIViewController *fromViewController; 29 | @property (nonatomic, weak) UIViewController *toViewController; 30 | 31 | @end 32 | 33 | @implementation MDNavigationAnimationController 34 | 35 | - (instancetype)init { 36 | return nil; 37 | } 38 | 39 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)navigationControllerOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController { 40 | self = [super init]; 41 | if (self) { 42 | self.duration = 0.25; 43 | self.navigationControllerOperation = navigationControllerOperation; 44 | self.fromViewController = fromViewController; 45 | self.toViewController = toViewController; 46 | self.snapshotEnable = YES; 47 | } 48 | return self; 49 | } 50 | 51 | - (NSTimeInterval)transitionDuration:(id)transitioning { 52 | return [self navigationControllerOperation] == UINavigationControllerOperationPush ? 0.35f : [self duration]; 53 | } 54 | 55 | - (void)animateTransition:(id )transitionContext; { 56 | if ([self navigationControllerOperation] == UINavigationControllerOperationPush) { 57 | [self pushTransitioning:transitionContext]; 58 | } else { 59 | [self popTransitioning:transitionContext]; 60 | } 61 | } 62 | 63 | - (void)pushTransitioning:(id)transitioning { 64 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 65 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 66 | 67 | NSTimeInterval duration = [self transitionDuration:transitioning]; 68 | 69 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 70 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 71 | CGRect fromViewDestination = CGRectOffset(initialFrame, -CGRectGetWidth(initialFrame) / 2., 0); 72 | 73 | UIView *overlayer = [[UIView alloc] initWithFrame:(CGRect){0, 0, initialFrame.size}]; 74 | overlayer.alpha = 0; 75 | overlayer.backgroundColor = [UIColor colorWithWhite:0 alpha:.2f]; 76 | 77 | UIView *fromView = [self isSnapshotEnabled] ? [fromViewController snapshot] : [fromViewController view]; 78 | 79 | fromViewController.view.hidden = [self isSnapshotEnabled]; 80 | toViewController.view.frame = CGRectOffset(finalFrame, CGRectGetWidth(finalFrame), 0); 81 | 82 | [fromView addSubview:overlayer]; 83 | [[transitioning containerView] addSubview:fromView]; 84 | [[transitioning containerView] addSubview:[toViewController view]]; 85 | 86 | [UIView animateWithDuration:duration 87 | delay:0.f 88 | options:UIViewAnimationOptionCurveEaseOut 89 | animations:^{ 90 | overlayer.alpha = 1.f; 91 | fromView.frame = fromViewDestination; 92 | toViewController.view.frame = finalFrame; 93 | } 94 | completion:^(BOOL finished) { 95 | toViewController.view.frame = finalFrame; 96 | fromViewController.view.frame = initialFrame; 97 | fromViewController.view.hidden = NO; 98 | 99 | [fromView removeFromSuperview]; 100 | [overlayer removeFromSuperview]; 101 | 102 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 103 | }]; 104 | } 105 | 106 | - (void)popTransitioning:(id)transitioning { 107 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 108 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 109 | 110 | NSTimeInterval duration = [self transitionDuration:transitioning]; 111 | 112 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 113 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 114 | CGRect toViewOrigin = CGRectOffset(finalFrame, -CGRectGetWidth(finalFrame) / 2., 0);; 115 | CGRect fromViewDestination = CGRectOffset(finalFrame, CGRectGetWidth(finalFrame), 0); 116 | 117 | toViewController.view.frame = toViewOrigin; 118 | fromViewController.view.hidden = [self isSnapshotEnabled]; 119 | 120 | UIView *fromView = [self isSnapshotEnabled] ? [fromViewController snapshot] : [fromViewController view]; 121 | fromView.frame = initialFrame; 122 | 123 | UIView *overlayer = [[UIView alloc] initWithFrame:(CGRect){0, 0, finalFrame.size}]; 124 | overlayer.backgroundColor = [UIColor colorWithWhite:0 alpha:.2f]; 125 | 126 | [[toViewController view] addSubview:overlayer]; 127 | [[transitioning containerView] addSubview:[toViewController view]]; 128 | [[transitioning containerView] addSubview:fromView]; 129 | [[transitioning containerView] bringSubviewToFront:fromView]; 130 | 131 | [UIView animateWithDuration:duration 132 | delay:0.0 133 | options:UIViewAnimationOptionCurveLinear 134 | animations:^{ 135 | overlayer.alpha = 0; 136 | fromView.frame = fromViewDestination; 137 | toViewController.view.frame = finalFrame; 138 | } 139 | completion:^(BOOL finished) { 140 | toViewController.view.frame = finalFrame; 141 | fromViewController.view.frame = initialFrame; 142 | fromViewController.view.hidden = NO; 143 | 144 | [fromView removeFromSuperview]; 145 | [overlayer removeFromSuperview]; 146 | // Reset toViewController's `snapshot` to nil 147 | if ([transitioning transitionWasCancelled]) { 148 | [[toViewController view] removeFromSuperview]; 149 | } else { 150 | toViewController.snapshot = nil; 151 | } 152 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 153 | }]; 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /MDTransitioning/MDNavigationControllerDelegate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface UINavigationController (MDPushAnimation) 24 | 25 | @property (nonatomic, assign) BOOL allowPushAnimation; 26 | 27 | @end 28 | 29 | // The default delegate of UINavigationControllerDelegate, to provide default implementation. 30 | @interface MDNavigationControllerDelegate : NSObject 31 | 32 | + (instancetype)defaultDelegate; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /MDTransitioning/MDNavigationControllerDelegate.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | #import "MDNavigationControllerDelegate.h" 24 | #import "MDNavigationAnimationController.h" 25 | #import "MDInteractionController.h" 26 | #import "UIViewController+MDNavigationTransitioning.h" 27 | #import "MDTransitioning+Private.h" 28 | 29 | @implementation UINavigationController (MDNavigationAnimationController) 30 | 31 | + (void)load{ 32 | static dispatch_once_t onceToken; 33 | dispatch_once(&onceToken, ^{ 34 | MDTransitioningMethodSwizzle([self class], @selector(pushViewController:animated:), @selector(swizzle_pushViewController:animated:)); 35 | }); 36 | } 37 | 38 | - (void)swizzle_pushViewController:(UIViewController*)viewController animated:(BOOL)animated{ 39 | if ([self delegate] == [MDNavigationControllerDelegate defaultDelegate]) { 40 | self.view.userInteractionEnabled = NO; 41 | 42 | if ([self topViewController] && ![[self topViewController] snapshot]) { 43 | self.topViewController.snapshot = [[self view] snapshotViewAfterScreenUpdates:NO]; 44 | } 45 | } 46 | 47 | [self swizzle_pushViewController:viewController animated:animated]; 48 | } 49 | 50 | - (BOOL)allowPushAnimation{ 51 | return [objc_getAssociatedObject(self, @selector(allowPushAnimation)) boolValue]; 52 | } 53 | 54 | - (void)setAllowPushAnimation:(BOOL)allowPushAnimation{ 55 | objc_setAssociatedObject(self, @selector(allowPushAnimation), @(allowPushAnimation), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 56 | } 57 | 58 | @end 59 | 60 | @implementation MDNavigationControllerDelegate 61 | 62 | + (instancetype)defaultDelegate;{ 63 | static MDNavigationControllerDelegate *delegate = nil; 64 | static dispatch_once_t onceToken; 65 | dispatch_once(&onceToken, ^{ 66 | delegate = [MDNavigationControllerDelegate new]; 67 | }); 68 | return delegate; 69 | } 70 | 71 | #pragma mark UINavigationControllerDelegate 72 | 73 | - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate{ 74 | navigationController.view.userInteractionEnabled = YES; 75 | } 76 | 77 | - (id)navigationController:(UINavigationController *)navigationController 78 | interactionControllerForAnimationController:(MDNavigationAnimationController *)animationController { 79 | return [[[animationController fromViewController] interactionController] interactiveTransition]; 80 | } 81 | 82 | - (id)navigationController:(UINavigationController *)navigationController 83 | animationControllerForOperation:(UINavigationControllerOperation)operation 84 | fromViewController:(UIViewController *)fromViewController 85 | toViewController:(UIViewController *)toViewController { 86 | if (operation == UINavigationControllerOperationPush && ![navigationController allowPushAnimation]) return nil; 87 | UIViewController *displayingViewController = operation == UINavigationControllerOperationPush ? toViewController : fromViewController; 88 | return [displayingViewController animationForNavigationOperation:operation fromViewController:fromViewController toViewController:toViewController]; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /MDTransitioning/MDPopInteractionController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDSwipeInteractionController.h" 23 | 24 | // The controller of pop interaction. 25 | @interface MDPopInteractionController : MDSwipeInteractionController 26 | 27 | // The horizontal offset is left edge of content view, default is 20.f. 28 | @property (nonatomic, assign) CGFloat horizontalOffset; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /MDTransitioning/MDPopInteractionController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDPopInteractionController.h" 22 | 23 | @implementation MDPopInteractionController 24 | 25 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 26 | if (self = [super initWithViewController:viewController]) { 27 | __block __weak id weak_self = self; 28 | self.horizontalOffset = 20.f; 29 | self.begin = ^(id interactiveTransition){ 30 | [[viewController navigationController] popViewControllerAnimated:YES]; 31 | }; 32 | self.allowSwipe = ^CGFloat(CGPoint location, CGPoint velocity) { 33 | return velocity.x > 0 && location.x < [weak_self horizontalOffset]; 34 | }; 35 | self.progress = ^CGFloat(CGPoint location, CGPoint translation, CGPoint velocity) { 36 | return translation.x / CGRectGetWidth([[viewController view] frame]); 37 | }; 38 | } 39 | return self; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /MDTransitioning/MDPresentionAnimationController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDAnimatedTransitioning.h" 23 | 24 | // The default presention animation controller base on MPresentionAnimatedTransitioning 25 | @interface MDPresentionAnimationController : NSObject 26 | 27 | // The duration of animation, default is 0.25f. 28 | @property (nonatomic, assign) NSTimeInterval duration; // Default is 0.25f. 29 | 30 | /** 31 | The designated initializer. If you subclass MDNavigationAnimationController, you must call the super implementation of this 32 | method. 33 | 34 | @param presentionAnimatedOperation presention controller operation, present or dismiss. 35 | @param fromViewController view controller appearing. 36 | @param toViewController view controller will be appearing. 37 | @return an instance of MDPresentionAnimationController or sub class. 38 | */ 39 | - (instancetype)initWithPresentionAnimatedOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController; 40 | 41 | - (instancetype)init DEPRECATED_MSG_ATTRIBUTE(" Use initWithOperation:fromViewController:toViewController: instead"); 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /MDTransitioning/MDPresentionAnimationController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDPresentionAnimationController.h" 22 | #import "UIViewController+MDPresentionTransitioning.h" 23 | 24 | @interface MDPresentionAnimationController () 25 | 26 | @property (nonatomic, assign) MDPresentionAnimatedOperation presentionAnimatedOperation; 27 | @property (nonatomic, weak) UIViewController *fromViewController; 28 | @property (nonatomic, weak) UIViewController *toViewController; 29 | 30 | @end 31 | 32 | @implementation MDPresentionAnimationController 33 | 34 | - (instancetype)init { 35 | return nil; 36 | } 37 | 38 | - (instancetype)initWithPresentionAnimatedOperation:(MDPresentionAnimatedOperation)presentionAnimatedOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController { 39 | self = [super init]; 40 | if (self) { 41 | NSParameterAssert(presentionAnimatedOperation != MDPresentionAnimatedOperationNone); 42 | 43 | self.duration = 0.25; 44 | self.presentionAnimatedOperation = presentionAnimatedOperation; 45 | self.fromViewController = fromViewController; 46 | self.toViewController = toViewController; 47 | } 48 | return self; 49 | } 50 | 51 | - (NSTimeInterval)transitionDuration:(id)transitioning { 52 | return [self duration]; 53 | } 54 | 55 | - (void)animateTransition:(id)transitioning { 56 | if ([self presentionAnimatedOperation] == MDPresentionAnimatedOperationPresent) { 57 | [self presentTransitioning:transitioning]; 58 | } else { 59 | [self dismissTransitioning:transitioning]; 60 | } 61 | } 62 | 63 | - (void)presentTransitioning:(id)transitioning { 64 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 65 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 66 | 67 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 68 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 69 | CGRect origin = CGRectOffset(initialFrame, 0, CGRectGetHeight(finalFrame)); 70 | 71 | toViewController.view.frame = origin; 72 | [[transitioning containerView] addSubview:[toViewController view]]; 73 | 74 | NSTimeInterval duration = [self transitionDuration:transitioning]; 75 | [UIView animateWithDuration:duration 76 | delay:0.0 77 | options:UIViewAnimationOptionCurveEaseIn 78 | animations:^{ 79 | toViewController.view.frame = finalFrame; 80 | } 81 | completion:^(BOOL finished) { 82 | [transitioning completeTransition:YES]; 83 | }]; 84 | } 85 | 86 | - (void)dismissTransitioning:(id)transitioning { 87 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 88 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 89 | 90 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 91 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 92 | CGRect destination = CGRectOffset(initialFrame, 0, CGRectGetHeight(finalFrame)); 93 | 94 | [[transitioning containerView] addSubview:[toViewController view]]; 95 | [[transitioning containerView] sendSubviewToBack:[toViewController view]]; 96 | 97 | NSTimeInterval duration = [self transitionDuration:transitioning]; 98 | [UIView animateWithDuration:duration 99 | delay:0.0 100 | options:UIViewAnimationOptionCurveEaseOut 101 | animations:^{ 102 | fromViewController.view.frame = destination; 103 | } 104 | completion:^(BOOL finished) { 105 | fromViewController.view.frame = initialFrame; 106 | 107 | if ([transitioning transitionWasCancelled]) { 108 | [[toViewController view] removeFromSuperview]; 109 | } 110 | 111 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 112 | }]; 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /MDTransitioning/MDPresentionControllerDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDPresentionControllerDelegate.h 3 | // MDTransitioning 4 | // 5 | // Created by 徐 林峰 on 2017/9/20. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MDPresentionControllerDelegate : NSObject 12 | 13 | @property (nonatomic, weak, readonly) UIViewController *referenceViewController; 14 | 15 | + (instancetype)delegateWithReferenceViewController:(UIViewController *)viewController; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /MDTransitioning/MDPresentionControllerDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDPresentionControllerDelegate.m 3 | // MDTransitioning 4 | // 5 | // Created by 徐 林峰 on 2017/9/20. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDPresentionControllerDelegate.h" 10 | #import "UIViewController+MDPresentionTransitioning.h" 11 | 12 | @interface MDPresentionControllerDelegate () 13 | 14 | @property (nonatomic, weak) UIViewController *referenceViewController; 15 | 16 | @end 17 | 18 | @implementation MDPresentionControllerDelegate 19 | 20 | + (MDPresentionControllerDelegate *)delegateWithReferenceViewControllerClass:(Class)referenceViewControllerClass{ 21 | static NSMutableDictionary *delegates = nil; 22 | static dispatch_once_t onceToken; 23 | dispatch_once(&onceToken, ^{ 24 | delegates = [NSMutableDictionary new]; 25 | }); 26 | NSString *key = NSStringFromClass(referenceViewControllerClass); 27 | MDPresentionControllerDelegate *delegate = delegates[key]; 28 | if (!delegate) { 29 | delegate = [MDPresentionControllerDelegate new]; 30 | delegates[key] = delegate; 31 | } 32 | return delegate; 33 | } 34 | 35 | + (instancetype)delegateWithReferenceViewController:(UIViewController *)viewController;{ 36 | MDPresentionControllerDelegate *delegate = [self delegateWithReferenceViewControllerClass:[viewController class]]; 37 | delegate.referenceViewController = viewController; 38 | return delegate; 39 | } 40 | 41 | #pragma mark - UIViewControllerTransitioningDelegate 42 | 43 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 44 | return [presented animationForPresentionOperation:MDPresentionAnimatedOperationPresent fromViewController:[self referenceViewController] toViewController:presented]; 45 | } 46 | 47 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed { 48 | return [dismissed animationForPresentionOperation:MDPresentionAnimatedOperationDismiss fromViewController:dismissed toViewController:[self referenceViewController]]; 49 | } 50 | 51 | //- (nullable id )interactionControllerForPresentation:(id )animator;{ 52 | // return [[[animator fromViewController] presentionInteractionController] interactiveTransition]; 53 | //} 54 | 55 | - (id )interactionControllerForDismissal:(id)animator;{ 56 | return [[[animator fromViewController] presentionInteractionController] interactiveTransition]; 57 | } 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /MDTransitioning/MDScaleNavigationAnimationController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | @interface MDScaleNavigationAnimationController : MDNavigationAnimationController 24 | 25 | @property (nonatomic, assign, getter=isSnapshotEnabled) BOOL snapshotEnable NS_UNAVAILABLE; 26 | 27 | // The offset to scale based on transition view frame. 28 | @property (nonatomic, assign) CGSize scaleOffset; 29 | 30 | // The background color of transion view will be changed, both push and pop. 31 | @property (nonatomic, strong) UIColor *transitionBackgroundColor; 32 | 33 | // The background color of transion view when pushing. 34 | @property (nonatomic, strong) UIColor *pushTransitionBackgroundColor; 35 | 36 | // The background color of transion view when popping. 37 | @property (nonatomic, strong) UIColor *popTransitionBackgroundColor; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MDTransitioning/MDScaleNavigationAnimationController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDScaleNavigationAnimationController.h" 22 | 23 | @implementation MDScaleNavigationAnimationController 24 | @dynamic snapshotEnable; 25 | 26 | - (instancetype)initWithNavigationControllerOperation:(UINavigationControllerOperation)navigationControllerOperation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController{ 27 | if (self = [super initWithNavigationControllerOperation:navigationControllerOperation fromViewController:fromViewController toViewController:toViewController]) { 28 | self.scaleOffset = CGSizeMake(20, 20); 29 | self.transitionBackgroundColor = [UIColor blackColor]; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)setTransitionBackgroundColor:(UIColor *)transitionBackgroundColor{ 35 | _transitionBackgroundColor = transitionBackgroundColor; 36 | 37 | self.pushTransitionBackgroundColor = transitionBackgroundColor; 38 | self.popTransitionBackgroundColor = transitionBackgroundColor; 39 | } 40 | 41 | - (void)setPushTransitionBackgroundColor:(UIColor *)pushTransitionBackgroundColor{ 42 | if (_pushTransitionBackgroundColor != pushTransitionBackgroundColor) { 43 | _pushTransitionBackgroundColor = pushTransitionBackgroundColor; 44 | 45 | if (_pushTransitionBackgroundColor != _transitionBackgroundColor) { 46 | _transitionBackgroundColor = nil; 47 | } 48 | } 49 | } 50 | 51 | - (void)setPopTransitionBackgroundColor:(UIColor *)popTransitionBackgroundColor{ 52 | if (_popTransitionBackgroundColor != popTransitionBackgroundColor) { 53 | _popTransitionBackgroundColor = popTransitionBackgroundColor; 54 | 55 | if (popTransitionBackgroundColor != _transitionBackgroundColor) { 56 | _transitionBackgroundColor = nil; 57 | } 58 | } 59 | } 60 | 61 | - (void)pushTransitioning:(id)transitioning { 62 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 63 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 64 | 65 | NSTimeInterval duration = [self transitionDuration:transitioning]; 66 | 67 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 68 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 69 | CGAffineTransform fromViewDestinationTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1 - self.scaleOffset.width / CGRectGetWidth(initialFrame), 1 - self.scaleOffset.height / CGRectGetHeight(initialFrame)); 70 | 71 | UIView *overlayer = [[UIView alloc] initWithFrame:(CGRect){0, 0, initialFrame.size}]; 72 | overlayer.alpha = 0; 73 | overlayer.backgroundColor = [UIColor colorWithWhite:0 alpha:.2f]; 74 | 75 | UIView *fromView = [fromViewController snapshot]; 76 | fromViewController.view.hidden = YES; 77 | 78 | UINavigationBar *navigationBar = [[fromViewController navigationController] navigationBar]; 79 | CGRect navigationBarFrame = [navigationBar frame]; 80 | 81 | navigationBar.frame = CGRectOffset(navigationBarFrame, CGRectGetWidth(navigationBarFrame), 0); 82 | toViewController.view.frame = CGRectOffset(finalFrame, CGRectGetWidth(finalFrame), 0); 83 | 84 | [fromView addSubview:overlayer]; 85 | [[transitioning containerView] addSubview:fromView]; 86 | [[transitioning containerView] addSubview:[toViewController view]]; 87 | 88 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 89 | UIColor *backgroundColor = [window backgroundColor]; 90 | 91 | UITabBar *tabBar = fromViewController.tabBarController.tabBar; 92 | BOOL tabBarHidden = tabBar.hidden; 93 | 94 | tabBar.hidden = YES; 95 | window.backgroundColor = self.pushTransitionBackgroundColor; 96 | [UIView animateWithDuration:duration 97 | delay:0.f 98 | options:UIViewAnimationOptionCurveEaseOut 99 | animations:^{ 100 | overlayer.alpha = 1.f; 101 | fromView.transform = fromViewDestinationTransform; 102 | toViewController.view.frame = finalFrame; 103 | navigationBar.frame = navigationBarFrame; 104 | } 105 | completion:^(BOOL finished) { 106 | fromView.transform = CGAffineTransformIdentity; 107 | navigationBar.frame = navigationBarFrame; 108 | toViewController.view.frame = finalFrame; 109 | fromViewController.view.frame = initialFrame; 110 | 111 | tabBar.hidden = tabBarHidden; 112 | fromViewController.view.hidden = NO; 113 | 114 | window.backgroundColor = backgroundColor; 115 | 116 | [fromView removeFromSuperview]; 117 | [overlayer removeFromSuperview]; 118 | 119 | [transitioning completeTransition:YES]; 120 | }]; 121 | } 122 | 123 | - (void)popTransitioning:(id)transitioning { 124 | UIViewController *fromViewController = [transitioning viewControllerForKey:UITransitionContextFromViewControllerKey]; 125 | UIViewController *toViewController = [transitioning viewControllerForKey:UITransitionContextToViewControllerKey]; 126 | NSTimeInterval duration = [self transitionDuration:transitioning]; 127 | 128 | CGRect initialFrame = [transitioning initialFrameForViewController:fromViewController]; 129 | CGRect finalFrame = [transitioning finalFrameForViewController:toViewController]; 130 | CGRect fromViewDestination = CGRectOffset(initialFrame, CGRectGetWidth(initialFrame), 0); 131 | CGAffineTransform toViewOriginTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1 - self.scaleOffset.width / CGRectGetWidth(finalFrame), 1 - self.scaleOffset.height / CGRectGetHeight(finalFrame)); 132 | 133 | UIView *overlayer = [[UIView alloc] initWithFrame:(CGRect){0, 0, initialFrame.size}]; 134 | overlayer.backgroundColor = [UIColor colorWithWhite:0 alpha:.2f]; 135 | 136 | UIView *fromView = [fromViewController snapshot]; 137 | fromViewController.view.hidden = YES; 138 | 139 | UIView *toView = [toViewController snapshot]; 140 | 141 | [toView addSubview:overlayer]; 142 | [[transitioning containerView] addSubview:[toViewController view]]; 143 | [[transitioning containerView] addSubview:toView]; 144 | [[transitioning containerView] addSubview:fromView]; 145 | [[transitioning containerView] bringSubviewToFront:fromView]; 146 | 147 | toView.transform = toViewOriginTransform; 148 | toViewController.view.hidden = YES; 149 | 150 | UITabBar *tabBar = fromViewController.tabBarController.tabBar; 151 | UINavigationBar *navigationBar = fromViewController.navigationController.navigationBar; 152 | 153 | BOOL tabBarHidden = tabBar.hidden; 154 | BOOL navigationBarHidden = navigationBar.hidden; 155 | 156 | tabBar.hidden = YES; 157 | navigationBar.hidden = YES; 158 | 159 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 160 | UIColor *backgroundColor = [window backgroundColor]; 161 | 162 | window.backgroundColor = self.popTransitionBackgroundColor; 163 | 164 | [UIView animateWithDuration:duration 165 | delay:0.0 166 | options:UIViewAnimationOptionCurveLinear 167 | animations:^{ 168 | overlayer.alpha = 0.f; 169 | fromView.frame = fromViewDestination; 170 | toView.transform = CGAffineTransformIdentity; 171 | } 172 | completion:^(BOOL finished) { 173 | toView.transform = CGAffineTransformIdentity; 174 | toViewController.view.frame = finalFrame; 175 | fromViewController.view.frame = initialFrame; 176 | 177 | window.backgroundColor = backgroundColor; 178 | 179 | tabBar.hidden = tabBarHidden; 180 | navigationBar.hidden = navigationBarHidden; 181 | toViewController.view.hidden = NO; 182 | fromViewController.view.hidden = NO; 183 | 184 | [overlayer removeFromSuperview]; 185 | [toView removeFromSuperview]; 186 | 187 | if ([transitioning transitionWasCancelled]) { 188 | [[toViewController view] removeFromSuperview]; 189 | } else { 190 | [fromView removeFromSuperview]; 191 | } 192 | [transitioning completeTransition:![transitioning transitionWasCancelled]]; 193 | }]; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /MDTransitioning/MDSwipeInteractionController.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "MDInteractionController.h" 23 | 24 | // The controller of swipe interaction. 25 | @interface MDSwipeInteractionController : NSObject 26 | 27 | - (instancetype)init DEPRECATED_MSG_ATTRIBUTE(" Use interactionControllerWithViewController: instead"); 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /MDTransitioning/MDSwipeInteractionController.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDSwipeInteractionController.h" 22 | 23 | @interface MDSwipeInteractionController () 24 | 25 | @property (nonatomic, assign) BOOL interactionInProgress; 26 | 27 | @property (nonatomic, weak) UIViewController *viewController; 28 | 29 | @property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer; 30 | 31 | @property (nonatomic, strong) id interactiveTransition; 32 | 33 | @end 34 | 35 | @implementation MDSwipeInteractionController 36 | @synthesize enable = _enable; 37 | @synthesize allowSwipe = _allowSwipe, progress = _progress; 38 | @synthesize begin = _begin, end = _end, update = _update; 39 | 40 | - (instancetype)init { 41 | return nil; 42 | } 43 | 44 | + (instancetype)interactionControllerWithViewController:(UIViewController *)viewController{ 45 | return [[self alloc] initWithViewController:viewController]; 46 | } 47 | 48 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 49 | if (self = [super init]) { 50 | self.viewController = viewController; 51 | 52 | [self prepareGestureRecognizerInView:[viewController view]]; 53 | } 54 | return self; 55 | } 56 | 57 | #pragma mark - accessor 58 | 59 | - (void)setEnable:(BOOL)enable{ 60 | self.panGestureRecognizer.enabled = enable; 61 | } 62 | 63 | - (BOOL)enable{ 64 | return [[self panGestureRecognizer] isEnabled]; 65 | } 66 | 67 | #pragma mark - protected 68 | 69 | - (id)requireInteractiveTransition;{ 70 | return [UIPercentDrivenInteractiveTransition new]; 71 | } 72 | 73 | - (void)prepareGestureRecognizerInView:(UIView*)view { 74 | self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGestureRecognizer:)]; 75 | self.panGestureRecognizer.delegate = self; 76 | [view addGestureRecognizer:[self panGestureRecognizer]]; 77 | } 78 | 79 | #pragma mark - UIPanGestureRecognizer handlers 80 | 81 | - (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)recognizer { 82 | CGPoint location = [recognizer locationInView:[[self viewController] view]]; 83 | CGPoint translation = [recognizer translationInView:[[self viewController] view]]; 84 | CGPoint velocity = [recognizer velocityInView:[[self viewController] view]]; 85 | 86 | if ([recognizer state] == UIGestureRecognizerStateBegan) { 87 | self.interactionInProgress = YES; 88 | // Create a interactive transition and pop the view controller 89 | self.interactiveTransition = [self requireInteractiveTransition]; 90 | if ([self begin]) { 91 | self.begin([self interactiveTransition]); 92 | } 93 | } else if ([recognizer state] == UIGestureRecognizerStateChanged) { 94 | CGFloat progress = [self progress] ? self.progress(location, translation, velocity) : 1.f; 95 | progress = MIN(1.0, MAX(0.0, progress)); 96 | // Update the interactive transition's progress 97 | if ([self update]) { 98 | self.update([self interactiveTransition], progress); 99 | } 100 | [[self interactiveTransition] updateInteractiveTransition:progress]; 101 | } else if ([recognizer state] == UIGestureRecognizerStateEnded || [recognizer state] == UIGestureRecognizerStateCancelled) { 102 | CGFloat progress = [self progress] ? self.progress(location, translation, velocity) : 1.f; 103 | progress = MIN(1.0, MAX(0.0, progress)); 104 | // Finish or cancel the interactive transition 105 | if (progress > 0.25) { 106 | [[self interactiveTransition] finishInteractiveTransition]; 107 | } else { 108 | [[self interactiveTransition] cancelInteractiveTransition]; 109 | } 110 | if ([self end]) { 111 | self.end([self interactiveTransition], progress > 0.25); 112 | } 113 | self.interactiveTransition = nil; 114 | self.interactionInProgress = NO; 115 | } 116 | } 117 | 118 | #pragma mark - UIGestureRecognizerDelegate 119 | 120 | - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)recognizer { 121 | CGPoint location = [recognizer locationInView:[[self viewController] view]]; 122 | CGPoint velocety = [recognizer velocityInView:[[self viewController] view]]; 123 | 124 | return recognizer == [self panGestureRecognizer] && [self allowSwipe] && self.allowSwipe(location, velocety); 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /MDTransitioning/MDTransitioning+Private.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import 23 | 24 | #ifndef MDTransitioningLoadCategory 25 | #define MDTransitioningLoadCategory(UNIQUE_NAME) @interface FORCELOAD_##UNIQUE_NAME :NSObject @end @implementation FORCELOAD_##UNIQUE_NAME @end 26 | #endif 27 | 28 | extern void MDTransitioningMethodSwizzle(Class class, SEL origSel, SEL altSel); 29 | -------------------------------------------------------------------------------- /MDTransitioning/MDTransitioning+Private.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDTransitioning+Private.h" 22 | 23 | void MDTransitioningMethodSwizzle(Class class, SEL origSel, SEL altSel) { 24 | Method origMethod = class_getInstanceMethod(class, origSel); 25 | Method altMethod = class_getInstanceMethod(class, altSel); 26 | 27 | class_addMethod(class, origSel, class_getMethodImplementation(class, origSel), method_getTypeEncoding(origMethod)); 28 | class_addMethod(class, altSel, class_getMethodImplementation(class, altSel), method_getTypeEncoding(altMethod)); 29 | 30 | method_exchangeImplementations(class_getInstanceMethod(class, origSel), class_getInstanceMethod(class, altSel)); 31 | } 32 | -------------------------------------------------------------------------------- /MDTransitioning/MDTransitioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | 23 | //! Project version number for MDTransitioning. 24 | FOUNDATION_EXPORT double MDTransitioningVersionNumber; 25 | 26 | //! Project version string for MDTransitioning. 27 | FOUNDATION_EXPORT const unsigned char MDTransitioningVersionString[]; 28 | 29 | // In this header, you should import all the public headers of your framework using statements like #import 30 | 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | #import 37 | #import 38 | #import 39 | #import 40 | #import 41 | #import 42 | #import 43 | 44 | #import 45 | #import 46 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipDismissInteractionController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipDismissInteractionController.h 3 | // MDTransitioning 4 | // 5 | // Created by xulinfeng on 2018/4/11. 6 | // Copyright © 2018年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDVerticalSwipInteractionController.h" 10 | 11 | @interface MDVerticalSwipDismissInteractionController : MDVerticalSwipInteractionController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipDismissInteractionController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipDismissInteractionController.m 3 | // MDTransitioning 4 | // 5 | // Created by xulinfeng on 2018/4/11. 6 | // Copyright © 2018年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDVerticalSwipDismissInteractionController.h" 10 | 11 | @implementation MDVerticalSwipDismissInteractionController 12 | 13 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 14 | if (self = [super initWithViewController:viewController]) { 15 | self.begin = ^(id interactiveTransition){ 16 | [viewController dismissViewControllerAnimated:YES completion:nil]; 17 | }; 18 | } 19 | return self; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipInteractionController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipInteractionController.h 3 | // Demo 4 | // 5 | // Created by Jave on 2017/9/24. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDSwipeInteractionController.h" 10 | 11 | @interface MDVerticalSwipInteractionController : MDSwipeInteractionController 12 | 13 | // The vertical offset is top edge of content view, default is 20.f. 14 | @property (nonatomic, assign) CGFloat verticalTranslation; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipInteractionController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipInteractionController.m 3 | // Demo 4 | // 5 | // Created by Jave on 2017/9/24. 6 | // Copyright © 2017年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDVerticalSwipInteractionController.h" 10 | 11 | @implementation MDVerticalSwipInteractionController 12 | 13 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 14 | if (self = [super initWithViewController:viewController]) { 15 | __block __weak MDVerticalSwipInteractionController *weak_self = self; 16 | self.verticalTranslation = 200.f; 17 | self.allowSwipe = ^CGFloat(CGPoint location, CGPoint velocity) { 18 | return velocity.y > 0; 19 | }; 20 | self.progress = ^CGFloat(CGPoint location, CGPoint translation, CGPoint velocity) { 21 | return translation.y / weak_self.verticalTranslation; 22 | }; 23 | } 24 | return self; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipPopInteractionController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipPopInteractionController.h 3 | // MDTransitioning 4 | // 5 | // Created by xulinfeng on 2018/4/11. 6 | // Copyright © 2018年 markejave. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MDVerticalSwipPopInteractionController : MDVerticalSwipInteractionController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /MDTransitioning/MDVerticalSwipPopInteractionController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MDVerticalSwipPopInteractionController.m 3 | // MDTransitioning 4 | // 5 | // Created by xulinfeng on 2018/4/11. 6 | // Copyright © 2018年 markejave. All rights reserved. 7 | // 8 | 9 | #import "MDVerticalSwipPopInteractionController.h" 10 | 11 | @implementation MDVerticalSwipPopInteractionController 12 | 13 | - (instancetype)initWithViewController:(UIViewController *)viewController{ 14 | if (self = [super initWithViewController:viewController]) { 15 | self.begin = ^(id interactiveTransition){ 16 | [[viewController navigationController] popViewControllerAnimated:YES]; 17 | }; 18 | } 19 | return self; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MDTransitioning/UIViewController+MDNavigationTransitioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDInteractionController.h" 22 | 23 | // The default implementation of MDNavigationPopController. 24 | @interface UIViewController (MDNavigationTransitioning) 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MDTransitioning/UIViewController+MDNavigationTransitioning.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "UIViewController+MDNavigationTransitioning.h" 22 | #import "MDTransitioning+Private.h" 23 | #import "MDPopInteractionController.h" 24 | #import "MDNavigationAnimationController.h" 25 | 26 | MDTransitioningLoadCategory(UIViewController_MDNavigationTransitioning) 27 | 28 | @implementation UINavigationController (MDNavigationTransitioning) 29 | 30 | + (void)load { 31 | static dispatch_once_t onceToken; 32 | dispatch_once(&onceToken, ^{ 33 | MDTransitioningMethodSwizzle([self class], @selector(pushViewController:animated:), @selector(MDNavigationTransitioning_pushViewController:animated:)); 34 | }); 35 | } 36 | 37 | - (void)MDNavigationTransitioning_pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ 38 | UIViewController *topViewController = (UIViewController *)[self topViewController]; 39 | if (topViewController.tabBarController) { 40 | topViewController.snapshot = [topViewController.tabBarController.view snapshotViewAfterScreenUpdates:NO]; 41 | } else { 42 | topViewController.snapshot = [self.view snapshotViewAfterScreenUpdates:NO]; 43 | } 44 | if (!self.navigationBarHidden) topViewController.navigationBarSnapshot = [self.navigationBar snapshotViewAfterScreenUpdates:NO]; 45 | 46 | [self MDNavigationTransitioning_pushViewController:viewController animated:animated]; 47 | } 48 | 49 | @end 50 | 51 | @implementation UIViewController (MDNavigationTransitioning) 52 | 53 | + (void)load { 54 | static dispatch_once_t onceToken; 55 | dispatch_once(&onceToken, ^{ 56 | MDTransitioningMethodSwizzle([self class], @selector(viewDidLoad), @selector(MDNavigationTransitioning_viewDidLoad)); 57 | MDTransitioningMethodSwizzle([self class], @selector(viewWillDisappear:), @selector(MDNavigationTransitioning_viewWillDisappear:)); 58 | }); 59 | } 60 | 61 | - (void)MDNavigationTransitioning_viewDidLoad{ 62 | [self MDNavigationTransitioning_viewDidLoad]; 63 | 64 | if ([self allowPopInteractive] && 65 | ![self allowCustomPopInteractive] && 66 | [self navigationController] != nil && 67 | [[self navigationController] delegate] != nil && 68 | [self navigationController] == [self parentViewController] && 69 | [[[self navigationController] viewControllers] firstObject] != self) { 70 | 71 | self.interactionController = [self requirePopInteractionController]; 72 | } 73 | } 74 | 75 | - (void)MDNavigationTransitioning_viewWillDisappear:(BOOL)animated { 76 | [self MDNavigationTransitioning_viewWillDisappear:animated]; 77 | // Being popped, take a snapshot 78 | if ([self isMovingFromParentViewController]) { 79 | self.snapshot = [[[self navigationController] view] snapshotViewAfterScreenUpdates:NO]; 80 | 81 | if (!self.navigationController.navigationBarHidden) { 82 | self.navigationBarSnapshot = [[[self navigationController] navigationBar] snapshotViewAfterScreenUpdates:NO]; 83 | } 84 | } 85 | } 86 | 87 | - (UIView *)snapshot{ 88 | return objc_getAssociatedObject(self, @selector(snapshot)); 89 | } 90 | 91 | - (void)setSnapshot:(UIView *)snapshot{ 92 | if (self.snapshot != snapshot) { 93 | objc_setAssociatedObject(self, @selector(snapshot), snapshot, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 94 | } 95 | } 96 | 97 | - (UIView *)navigationBarSnapshot{ 98 | return objc_getAssociatedObject(self, @selector(navigationBarSnapshot)); 99 | } 100 | 101 | - (void)setNavigationBarSnapshot:(UIView *)navigationBarSnapshot{ 102 | if (self.navigationBarSnapshot != navigationBarSnapshot) { 103 | objc_setAssociatedObject(self, @selector(navigationBarSnapshot), navigationBarSnapshot, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 104 | } 105 | } 106 | 107 | - (void)setAllowPopInteractive:(BOOL)allowPopInteractive{ 108 | objc_setAssociatedObject(self, @selector(allowPopInteractive), @(allowPopInteractive), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 109 | } 110 | 111 | - (BOOL)allowPopInteractive{ 112 | id allowPopInteractiveAssociatedObject = objc_getAssociatedObject(self, @selector(allowPopInteractive)); 113 | if (!allowPopInteractiveAssociatedObject) { 114 | allowPopInteractiveAssociatedObject = @YES; 115 | self.allowPopInteractive = YES; 116 | } 117 | return [allowPopInteractiveAssociatedObject boolValue]; 118 | } 119 | 120 | - (void)setAllowCustomPopInteractive:(BOOL)allowCustomPopInteractive{ 121 | objc_setAssociatedObject(self, @selector(allowCustomPopInteractive), @(allowCustomPopInteractive), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 122 | } 123 | 124 | - (BOOL)allowCustomPopInteractive{ 125 | return [objc_getAssociatedObject(self, @selector(allowCustomPopInteractive)) boolValue]; 126 | } 127 | 128 | - (id)interactionController{ 129 | return objc_getAssociatedObject(self, @selector(interactionController)); 130 | } 131 | 132 | - (void)setInteractionController:(id)interactionController{ 133 | if ([self interactionController] != interactionController) { 134 | objc_setAssociatedObject(self, @selector(interactionController), interactionController, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 135 | } 136 | } 137 | 138 | - (id)requirePopInteractionController;{ 139 | return [MDPopInteractionController interactionControllerWithViewController:self]; 140 | } 141 | 142 | - (id)animationForNavigationOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 143 | return [[MDNavigationAnimationController alloc] initWithNavigationControllerOperation:operation fromViewController:fromViewController toViewController:toViewController]; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /MDTransitioning/UIViewController+MDPresentionTransitioning.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import "MDInteractionController.h" 22 | 23 | // The default implementation of MDPresentionController. 24 | @interface UIViewController (MDPresentionTransitioning) 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MDTransitioning/UIViewController+MDPresentionTransitioning.m: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Modool. All rights reserved. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #import 22 | #import "UIViewController+MDPresentionTransitioning.h" 23 | #import "MDTransitioning+Private.h" 24 | #import "MDPresentionAnimationController.h" 25 | 26 | MDTransitioningLoadCategory(UIViewController_MDPresentionTransitioning) 27 | 28 | @implementation UIViewController (MDPresentionTransitioning) 29 | 30 | - (void)setPresentionInteractionController:(id)presentionInteractionController{ 31 | objc_setAssociatedObject(self, @selector(presentionInteractionController), presentionInteractionController, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 32 | } 33 | 34 | - (id)presentionInteractionController{ 35 | return objc_getAssociatedObject(self, @selector(presentionInteractionController)); 36 | } 37 | 38 | - (id)animationForPresentionOperation:(MDPresentionAnimatedOperation)operation fromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;{ 39 | return [[MDPresentionAnimationController alloc] initWithPresentionAnimatedOperation:operation fromViewController:fromViewController toViewController:toViewController]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MDTransitioning 2 | 3 | [![](https://img.shields.io/travis/rust-lang/rust.svg?style=flat)](https://github.com/Modool) 4 | [![](https://img.shields.io/badge/language-Object--C-1eafeb.svg?style=flat)](https://developer.apple.com/Objective-C) 5 | [![](https://img.shields.io/badge/license-MIT-353535.svg?style=flat)](https://developer.apple.com/iphone/index.action) 6 | [![](https://img.shields.io/badge/platform-iOS-lightgrey.svg?style=flat)](https://github.com/Modool) 7 | [![](https://img.shields.io/badge/QQ群-662988771-red.svg)](http://wpa.qq.com/msgrd?v=3&uin=662988771&site=qq&menu=yes) 8 | 9 | ## Introduction 10 | 11 | - Animation based with transtion, easy to custom gesture control by developer. 12 | - Quick Integrate global gesture, sideslip or local animation 13 | 14 | ## How To Get Started 15 | 16 | * Download `MDTransitioning` and try run example app 17 | 18 | ## Installation 19 | 20 | 21 | * Installation with CocoaPods 22 | 23 | ``` 24 | source 'https://github.com/Modool/cocoapods-specs.git' 25 | platform :ios, '8.0' 26 | 27 | target 'TargetName' do 28 | pod 'MDTransitioning', '~> 1.0.2' 29 | end 30 | 31 | ``` 32 | 33 | * Installation with Carthage 34 | 35 | ``` 36 | github "Modool/MDTransitioning" ~> 1.0.2 37 | ``` 38 | 39 | * Manual Import 40 | 41 | ``` 42 | drag “MDTransitioning” directory into your project 43 | 44 | ``` 45 | 46 | 47 | ## Requirements 48 | - Requires ARC 49 | 50 | ## Architecture 51 | 52 | ### AnimatedTransitioning 53 | 54 | * `` 55 | * `` 56 | * `` 57 | * `` 58 | * `MDNavigationAnimationController` 59 | * `MDPresentionAnimationController` 60 | 61 | ### InteractiveController 62 | 63 | * `` 64 | * `` 65 | * `` 66 | * `MDSwipeInteractionController` 67 | * `MDPopInteractionController` 68 | * `UIViewController+MDNavigationTransitioning` 69 | * `UIViewController+MDPresentionTransitioning` 70 | 71 | ### ImageViewController 72 | 73 | * `AnimatedTransitioning` 74 | * `MDImageZoomAnimationController` 75 | * `InteractiveTransition` 76 | * `MDImageDismissInteractionController` 77 | * `MDImageDraggingDismissInteractionController` 78 | * `MDImageViewController` 79 | 80 | ## Usage 81 | 82 | * Demo FYI 83 | 84 | ## Update History 85 | 86 | * 2017.7.30 Add README and adjust project class name. 87 | 88 | ## License 89 | `MDTransitioning` is released under the MIT license. See LICENSE for details. 90 | 91 | ## Article 92 | 93 | Article support if you want to see more extension or demo. Go. 94 | 95 | ## Communication 96 | 97 | 98 | -------------------------------------------------------------------------------- /snapshots/custom_present.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/custom_present.gif -------------------------------------------------------------------------------- /snapshots/custom_push.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/custom_push.gif -------------------------------------------------------------------------------- /snapshots/image_present.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/image_present.gif -------------------------------------------------------------------------------- /snapshots/scale_push.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/scale_push.gif -------------------------------------------------------------------------------- /snapshots/system_present.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/system_present.gif -------------------------------------------------------------------------------- /snapshots/system_push.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/system_push.gif -------------------------------------------------------------------------------- /snapshots/vertical_pop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Modool/MDTransitioning/d2f6ee1b9cbcc4e59d2108d27612cad540198542/snapshots/vertical_pop.gif --------------------------------------------------------------------------------