├── .gitignore ├── .swift-version ├── Images └── music.gif ├── LICENSE ├── Movin.podspec ├── Proj ├── Demo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── DetailViewController.swift │ ├── Info.plist │ ├── InteractiveAnimationViewController.swift │ ├── InteractiveTransitionViewController.swift │ ├── ModalViewController.swift │ ├── PresentTransitionViewController.swift │ ├── PushTransitionViewController.swift │ └── ViewController.swift ├── Movin.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Movin.xcscheme ├── Movin.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── MovinPlayground.playground │ ├── Contents.swift │ └── contents.xcplayground ├── README.md └── Sources ├── AnimatedTransitioning.swift ├── Animations.swift ├── Extensions.swift ├── GestureAnimating.swift ├── GestureTransitioning.swift ├── Info.plist ├── InteractiveTransitioning.swift ├── Movin.h ├── Movin.swift ├── Shorthands.swift ├── TimingCurve.swift └── Transition.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/xcode,swift 2 | 3 | # Mac OS X 4 | .DS_Store 5 | 6 | ### Xcode ### 7 | # Xcode 8 | # 9 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 10 | 11 | ## Build generated 12 | build/ 13 | DerivedData/ 14 | 15 | ## Various settings 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | #xcuserdata/ 25 | 26 | ## Other 27 | *.moved-aside 28 | *.xccheckout 29 | *.xcscmblueprint 30 | 31 | 32 | ### Swift ### 33 | # Xcode 34 | # 35 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 36 | 37 | ## Build generated 38 | build/ 39 | DerivedData/ 40 | 41 | ## Various settings 42 | *.pbxuser 43 | !default.pbxuser 44 | *.mode1v3 45 | !default.mode1v3 46 | *.mode2v3 47 | !default.mode2v3 48 | *.perspectivev3 49 | !default.perspectivev3 50 | xcuserdata/ 51 | 52 | ## Other 53 | *.moved-aside 54 | *.xcuserstate 55 | 56 | ## Obj-C/Swift specific 57 | *.hmap 58 | *.ipa 59 | *.dSYM.zip 60 | *.dSYM 61 | 62 | ## Playgrounds 63 | timeline.xctimeline 64 | playground.xcworkspace 65 | 66 | # Swift Package Manager 67 | # 68 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 69 | # Packages/ 70 | .build/ 71 | 72 | # CocoaPods 73 | # 74 | # We recommend against adding the Pods directory to your .gitignore. However 75 | # you should judge for yourself, the pros and cons are mentioned at: 76 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 77 | # 78 | Pods/ 79 | 80 | # Carthage 81 | # 82 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 83 | # Carthage/Checkouts 84 | 85 | # Carthage/Build 86 | 87 | # fastlane 88 | # 89 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 90 | # screenshots whenever they are needed. 91 | # For more information about the recommended setup visit: 92 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 93 | 94 | fastlane/report.xml 95 | fastlane/Preview.html 96 | fastlane/screenshots 97 | fastlane/test_output 98 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /Images/music.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxxAIRINxxx/Movin/fffaa61e624fcb9887cfc4d995557f305305dbdd/Images/music.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 xxxAIRINxxx 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 11 | all 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 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Movin.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Movin" 3 | s.version = "1.2.0" 4 | s.summary = "UIViewPropertyAnimator based View Transition Animator." 5 | s.homepage = "https://github.com/xxxAIRINxxx/Movin" 6 | s.license = 'MIT' 7 | s.author = { "Airin" => "xl1138@gmail.com" } 8 | s.source = { :git => "https://github.com/xxxAIRINxxx/Movin.git", :tag => s.version.to_s } 9 | 10 | s.requires_arc = true 11 | s.platform = :ios, '10.0' 12 | 13 | s.source_files = 'Sources/*.swift' 14 | end 15 | -------------------------------------------------------------------------------- /Proj/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 914D998D2112AE6500FE7FED /* Movin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 914D998C2112AE5200FE7FED /* Movin.framework */; }; 11 | 914D998E2112AE6500FE7FED /* Movin.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 914D998C2112AE5200FE7FED /* Movin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | 91D4563F2112C120004A3F5E /* PresentTransitionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D4563E2112C120004A3F5E /* PresentTransitionViewController.swift */; }; 13 | 91D456412112C13D004A3F5E /* ModalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456402112C13D004A3F5E /* ModalViewController.swift */; }; 14 | 91D456432112C269004A3F5E /* InteractiveAnimationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456422112C269004A3F5E /* InteractiveAnimationViewController.swift */; }; 15 | 91D456452112C296004A3F5E /* InteractiveTransitionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456442112C296004A3F5E /* InteractiveTransitionViewController.swift */; }; 16 | 91F66E0E211A882600179857 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F66E0D211A882600179857 /* DetailViewController.swift */; }; 17 | 91FBFB271C5904EA0064E23C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FBFB261C5904EA0064E23C /* AppDelegate.swift */; }; 18 | 91FBFB291C5904EA0064E23C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FBFB281C5904EA0064E23C /* ViewController.swift */; }; 19 | 91FBFB2C1C5904EA0064E23C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 91FBFB2A1C5904EA0064E23C /* Main.storyboard */; }; 20 | 91FBFB2E1C5904EA0064E23C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 91FBFB2D1C5904EA0064E23C /* Assets.xcassets */; }; 21 | 91FBFB311C5904EA0064E23C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 91FBFB2F1C5904EA0064E23C /* LaunchScreen.storyboard */; }; 22 | 91FD68C5211962D8008DD16A /* PushTransitionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FD68C4211962D8008DD16A /* PushTransitionViewController.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 914D998B2112AE5200FE7FED /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 914D99872112AE5200FE7FED /* Movin.xcodeproj */; 29 | proxyType = 2; 30 | remoteGlobalIDString = 91B9EB1C1C59AB9700426490; 31 | remoteInfo = Movin; 32 | }; 33 | 914D998F2112AE6500FE7FED /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 914D99872112AE5200FE7FED /* Movin.xcodeproj */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 91B9EB1B1C59AB9700426490; 38 | remoteInfo = Movin; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXCopyFilesBuildPhase section */ 43 | 916DFDF621104A4E009B365C /* Embed Frameworks */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = ""; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | 914D998E2112AE6500FE7FED /* Movin.framework in Embed Frameworks */, 50 | ); 51 | name = "Embed Frameworks"; 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXCopyFilesBuildPhase section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 914D99852112AE3A00FE7FED /* Movin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Movin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 914D99872112AE5200FE7FED /* Movin.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Movin.xcodeproj; sourceTree = ""; }; 59 | 91D4563E2112C120004A3F5E /* PresentTransitionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentTransitionViewController.swift; sourceTree = ""; }; 60 | 91D456402112C13D004A3F5E /* ModalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalViewController.swift; sourceTree = ""; }; 61 | 91D456422112C269004A3F5E /* InteractiveAnimationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveAnimationViewController.swift; sourceTree = ""; }; 62 | 91D456442112C296004A3F5E /* InteractiveTransitionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveTransitionViewController.swift; sourceTree = ""; }; 63 | 91F66E0D211A882600179857 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 64 | 91FBFB231C5904E90064E23C /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 91FBFB261C5904EA0064E23C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 66 | 91FBFB281C5904EA0064E23C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 67 | 91FBFB2B1C5904EA0064E23C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 68 | 91FBFB2D1C5904EA0064E23C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 69 | 91FBFB301C5904EA0064E23C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 70 | 91FBFB321C5904EB0064E23C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | 91FD68C4211962D8008DD16A /* PushTransitionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushTransitionViewController.swift; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 91FBFB201C5904E90064E23C /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 914D998D2112AE6500FE7FED /* Movin.framework in Frameworks */, 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXFrameworksBuildPhase section */ 84 | 85 | /* Begin PBXGroup section */ 86 | 914D99842112AE3A00FE7FED /* Frameworks */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 914D99852112AE3A00FE7FED /* Movin.framework */, 90 | ); 91 | name = Frameworks; 92 | sourceTree = ""; 93 | }; 94 | 914D99882112AE5200FE7FED /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 914D998C2112AE5200FE7FED /* Movin.framework */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 91FBFB1A1C5904E90064E23C = { 103 | isa = PBXGroup; 104 | children = ( 105 | 914D99872112AE5200FE7FED /* Movin.xcodeproj */, 106 | 91FBFB251C5904EA0064E23C /* Demo */, 107 | 914D99842112AE3A00FE7FED /* Frameworks */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | 91FBFB241C5904E90064E23C /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 91FBFB231C5904E90064E23C /* Demo.app */, 115 | ); 116 | name = Products; 117 | path = ..; 118 | sourceTree = ""; 119 | }; 120 | 91FBFB251C5904EA0064E23C /* Demo */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 91FBFB261C5904EA0064E23C /* AppDelegate.swift */, 124 | 91FBFB281C5904EA0064E23C /* ViewController.swift */, 125 | 91FD68C4211962D8008DD16A /* PushTransitionViewController.swift */, 126 | 91D4563E2112C120004A3F5E /* PresentTransitionViewController.swift */, 127 | 91D456422112C269004A3F5E /* InteractiveAnimationViewController.swift */, 128 | 91D456442112C296004A3F5E /* InteractiveTransitionViewController.swift */, 129 | 91F66E0D211A882600179857 /* DetailViewController.swift */, 130 | 91D456402112C13D004A3F5E /* ModalViewController.swift */, 131 | 91FBFB2A1C5904EA0064E23C /* Main.storyboard */, 132 | 91FBFB2D1C5904EA0064E23C /* Assets.xcassets */, 133 | 91FBFB2F1C5904EA0064E23C /* LaunchScreen.storyboard */, 134 | 91FBFB321C5904EB0064E23C /* Info.plist */, 135 | 91FBFB241C5904E90064E23C /* Products */, 136 | ); 137 | path = Demo; 138 | sourceTree = ""; 139 | }; 140 | /* End PBXGroup section */ 141 | 142 | /* Begin PBXNativeTarget section */ 143 | 91FBFB221C5904E90064E23C /* Demo */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = 91FBFB351C5904EB0064E23C /* Build configuration list for PBXNativeTarget "Demo" */; 146 | buildPhases = ( 147 | 91FBFB1F1C5904E90064E23C /* Sources */, 148 | 91FBFB201C5904E90064E23C /* Frameworks */, 149 | 91FBFB211C5904E90064E23C /* Resources */, 150 | 916DFDF621104A4E009B365C /* Embed Frameworks */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | 914D99902112AE6500FE7FED /* PBXTargetDependency */, 156 | ); 157 | name = Demo; 158 | productName = Demo; 159 | productReference = 91FBFB231C5904E90064E23C /* Demo.app */; 160 | productType = "com.apple.product-type.application"; 161 | }; 162 | /* End PBXNativeTarget section */ 163 | 164 | /* Begin PBXProject section */ 165 | 91FBFB1B1C5904E90064E23C /* Project object */ = { 166 | isa = PBXProject; 167 | attributes = { 168 | LastSwiftUpdateCheck = 0720; 169 | LastUpgradeCheck = 1020; 170 | ORGANIZATIONNAME = xxxAIRINxxx; 171 | TargetAttributes = { 172 | 91FBFB221C5904E90064E23C = { 173 | CreatedOnToolsVersion = 7.2; 174 | DevelopmentTeam = P599PJHMNF; 175 | DevelopmentTeamName = "TAKASHI YOSHINAGA"; 176 | LastSwiftMigration = 0900; 177 | }; 178 | }; 179 | }; 180 | buildConfigurationList = 91FBFB1E1C5904E90064E23C /* Build configuration list for PBXProject "Demo" */; 181 | compatibilityVersion = "Xcode 3.2"; 182 | developmentRegion = en; 183 | hasScannedForEncodings = 0; 184 | knownRegions = ( 185 | en, 186 | Base, 187 | ); 188 | mainGroup = 91FBFB1A1C5904E90064E23C; 189 | productRefGroup = 91FBFB241C5904E90064E23C /* Products */; 190 | projectDirPath = ""; 191 | projectReferences = ( 192 | { 193 | ProductGroup = 914D99882112AE5200FE7FED /* Products */; 194 | ProjectRef = 914D99872112AE5200FE7FED /* Movin.xcodeproj */; 195 | }, 196 | ); 197 | projectRoot = ""; 198 | targets = ( 199 | 91FBFB221C5904E90064E23C /* Demo */, 200 | ); 201 | }; 202 | /* End PBXProject section */ 203 | 204 | /* Begin PBXReferenceProxy section */ 205 | 914D998C2112AE5200FE7FED /* Movin.framework */ = { 206 | isa = PBXReferenceProxy; 207 | fileType = wrapper.framework; 208 | path = Movin.framework; 209 | remoteRef = 914D998B2112AE5200FE7FED /* PBXContainerItemProxy */; 210 | sourceTree = BUILT_PRODUCTS_DIR; 211 | }; 212 | /* End PBXReferenceProxy section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | 91FBFB211C5904E90064E23C /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 91FBFB311C5904EA0064E23C /* LaunchScreen.storyboard in Resources */, 220 | 91FBFB2E1C5904EA0064E23C /* Assets.xcassets in Resources */, 221 | 91FBFB2C1C5904EA0064E23C /* Main.storyboard in Resources */, 222 | ); 223 | runOnlyForDeploymentPostprocessing = 0; 224 | }; 225 | /* End PBXResourcesBuildPhase section */ 226 | 227 | /* Begin PBXSourcesBuildPhase section */ 228 | 91FBFB1F1C5904E90064E23C /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | 91D456452112C296004A3F5E /* InteractiveTransitionViewController.swift in Sources */, 233 | 91D456412112C13D004A3F5E /* ModalViewController.swift in Sources */, 234 | 91D456432112C269004A3F5E /* InteractiveAnimationViewController.swift in Sources */, 235 | 91FD68C5211962D8008DD16A /* PushTransitionViewController.swift in Sources */, 236 | 91FBFB291C5904EA0064E23C /* ViewController.swift in Sources */, 237 | 91D4563F2112C120004A3F5E /* PresentTransitionViewController.swift in Sources */, 238 | 91FBFB271C5904EA0064E23C /* AppDelegate.swift in Sources */, 239 | 91F66E0E211A882600179857 /* DetailViewController.swift in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXSourcesBuildPhase section */ 244 | 245 | /* Begin PBXTargetDependency section */ 246 | 914D99902112AE6500FE7FED /* PBXTargetDependency */ = { 247 | isa = PBXTargetDependency; 248 | name = Movin; 249 | targetProxy = 914D998F2112AE6500FE7FED /* PBXContainerItemProxy */; 250 | }; 251 | /* End PBXTargetDependency section */ 252 | 253 | /* Begin PBXVariantGroup section */ 254 | 91FBFB2A1C5904EA0064E23C /* Main.storyboard */ = { 255 | isa = PBXVariantGroup; 256 | children = ( 257 | 91FBFB2B1C5904EA0064E23C /* Base */, 258 | ); 259 | name = Main.storyboard; 260 | sourceTree = ""; 261 | }; 262 | 91FBFB2F1C5904EA0064E23C /* LaunchScreen.storyboard */ = { 263 | isa = PBXVariantGroup; 264 | children = ( 265 | 91FBFB301C5904EA0064E23C /* Base */, 266 | ); 267 | name = LaunchScreen.storyboard; 268 | sourceTree = ""; 269 | }; 270 | /* End PBXVariantGroup section */ 271 | 272 | /* Begin XCBuildConfiguration section */ 273 | 91FBFB331C5904EB0064E23C /* Debug */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_COMMA = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 287 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 288 | CLANG_WARN_EMPTY_BODY = YES; 289 | CLANG_WARN_ENUM_CONVERSION = YES; 290 | CLANG_WARN_INFINITE_RECURSION = YES; 291 | CLANG_WARN_INT_CONVERSION = YES; 292 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 293 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 294 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 296 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 297 | CLANG_WARN_STRICT_PROTOTYPES = YES; 298 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 299 | CLANG_WARN_UNREACHABLE_CODE = YES; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 302 | COPY_PHASE_STRIP = NO; 303 | DEBUG_INFORMATION_FORMAT = dwarf; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | ENABLE_TESTABILITY = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu99; 307 | GCC_DYNAMIC_NO_PIC = NO; 308 | GCC_NO_COMMON_BLOCKS = YES; 309 | GCC_OPTIMIZATION_LEVEL = 0; 310 | GCC_PREPROCESSOR_DEFINITIONS = ( 311 | "DEBUG=1", 312 | "$(inherited)", 313 | ); 314 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 315 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 316 | GCC_WARN_UNDECLARED_SELECTOR = YES; 317 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 318 | GCC_WARN_UNUSED_FUNCTION = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 321 | MTL_ENABLE_DEBUG_INFO = YES; 322 | ONLY_ACTIVE_ARCH = YES; 323 | SDKROOT = iphoneos; 324 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 325 | }; 326 | name = Debug; 327 | }; 328 | 91FBFB341C5904EB0064E23C /* Release */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 334 | CLANG_CXX_LIBRARY = "libc++"; 335 | CLANG_ENABLE_MODULES = YES; 336 | CLANG_ENABLE_OBJC_ARC = YES; 337 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 338 | CLANG_WARN_BOOL_CONVERSION = YES; 339 | CLANG_WARN_COMMA = YES; 340 | CLANG_WARN_CONSTANT_CONVERSION = YES; 341 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 342 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 343 | CLANG_WARN_EMPTY_BODY = YES; 344 | CLANG_WARN_ENUM_CONVERSION = YES; 345 | CLANG_WARN_INFINITE_RECURSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 349 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 350 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 351 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 352 | CLANG_WARN_STRICT_PROTOTYPES = YES; 353 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 354 | CLANG_WARN_UNREACHABLE_CODE = YES; 355 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 356 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 357 | COPY_PHASE_STRIP = NO; 358 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 359 | ENABLE_NS_ASSERTIONS = NO; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | GCC_C_LANGUAGE_STANDARD = gnu99; 362 | GCC_NO_COMMON_BLOCKS = YES; 363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 365 | GCC_WARN_UNDECLARED_SELECTOR = YES; 366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 367 | GCC_WARN_UNUSED_FUNCTION = YES; 368 | GCC_WARN_UNUSED_VARIABLE = YES; 369 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 370 | MTL_ENABLE_DEBUG_INFO = NO; 371 | SDKROOT = iphoneos; 372 | VALIDATE_PRODUCT = YES; 373 | }; 374 | name = Release; 375 | }; 376 | 91FBFB361C5904EB0064E23C /* Debug */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 380 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 381 | CODE_SIGN_IDENTITY = "iPhone Developer"; 382 | DEVELOPMENT_TEAM = P599PJHMNF; 383 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 384 | INFOPLIST_FILE = Demo/Info.plist; 385 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 386 | PRODUCT_BUNDLE_IDENTIFIER = xxxAIRINxxx.Demo; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 389 | SWIFT_VERSION = 5.0; 390 | }; 391 | name = Debug; 392 | }; 393 | 91FBFB371C5904EB0064E23C /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 397 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 398 | CODE_SIGN_IDENTITY = "iPhone Developer"; 399 | DEVELOPMENT_TEAM = P599PJHMNF; 400 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 401 | INFOPLIST_FILE = Demo/Info.plist; 402 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 403 | PRODUCT_BUNDLE_IDENTIFIER = xxxAIRINxxx.Demo; 404 | PRODUCT_NAME = "$(TARGET_NAME)"; 405 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 406 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 407 | SWIFT_VERSION = 5.0; 408 | }; 409 | name = Release; 410 | }; 411 | /* End XCBuildConfiguration section */ 412 | 413 | /* Begin XCConfigurationList section */ 414 | 91FBFB1E1C5904E90064E23C /* Build configuration list for PBXProject "Demo" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | 91FBFB331C5904EB0064E23C /* Debug */, 418 | 91FBFB341C5904EB0064E23C /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | 91FBFB351C5904EB0064E23C /* Build configuration list for PBXNativeTarget "Demo" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 91FBFB361C5904EB0064E23C /* Debug */, 427 | 91FBFB371C5904EB0064E23C /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | /* End XCConfigurationList section */ 433 | }; 434 | rootObject = 91FBFB1B1C5904E90064E23C /* Project object */; 435 | } 436 | -------------------------------------------------------------------------------- /Proj/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Proj/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/01. 6 | // Copyright © 2016 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | @UIApplicationMain 13 | final class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 18 | Movin.isDebugPrintEnabled = true 19 | return true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Proj/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" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Proj/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 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Proj/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 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | -------------------------------------------------------------------------------- /Proj/Demo/DetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class DetailViewController: UIViewController { 12 | 13 | @IBOutlet private(set) weak var contentView: UIView! 14 | 15 | deinit { 16 | print("denit DetailViewController") 17 | } 18 | 19 | @IBAction private func tapCloseButton() { 20 | _ = self.navigationController?.popViewController(animated: true) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Proj/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Movin Demo 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Proj/Demo/InteractiveAnimationViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InteractiveAnimationViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class InteractiveAnimationViewController: UIViewController { 13 | 14 | @IBOutlet private weak var contentView: UIView! 15 | 16 | private var movin: Movin? 17 | 18 | private var originalFrame: CGRect = CGRect.zero 19 | 20 | override func viewDidAppear(_ animated: Bool) { 21 | super.viewDidAppear(animated) 22 | 23 | self.originalFrame = self.contentView.frame 24 | self.setup() 25 | } 26 | 27 | private func setup() { 28 | if #available(iOS 11.0, *) { 29 | self.movin = Movin(1.0, TimingCurve(curve: .easeInOut, dampingRatio: 0.8)) 30 | } else { 31 | self.movin = Movin(1.0) 32 | } 33 | 34 | self.movin!.addAnimations([ 35 | self.contentView.mvn.alpha.to(0.5), 36 | self.contentView.mvn.point.from(self.originalFrame.origin).to(CGPoint(x: 100, y: 150)), 37 | self.contentView.mvn.cornerRadius.to(15), 38 | ]) 39 | 40 | let gesture = GestureAnimating(self.contentView, .none(self.view), self.view.mvn.halfSize) 41 | self.movin!.startAnimation(.interactive(gesture)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Proj/Demo/InteractiveTransitionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InteractiveTransitionViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class InteractiveTransitionViewController: UIViewController { 13 | 14 | @IBOutlet private weak var contentView: UIView! 15 | 16 | private var movin: Movin? 17 | 18 | override func viewDidAppear(_ animated: Bool) { 19 | super.viewDidAppear(animated) 20 | 21 | self.setup() 22 | } 23 | 24 | private func setup() { 25 | if #available(iOS 11.0, *) { 26 | self.movin = Movin(1.0, TimingCurve(curve: .easeInOut, dampingRatio: 0.8)) 27 | } else { 28 | self.movin = Movin(1.0) 29 | } 30 | 31 | let modal = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as! ModalViewController 32 | modal.view.layoutIfNeeded() 33 | 34 | self.movin!.addAnimations([ 35 | self.contentView.mvn.alpha.to(0.5), 36 | self.contentView.mvn.frame.to(CGRect(x: 100, y: 150, width: 30, height: 30)), 37 | self.contentView.mvn.backgroundColor.to(UIColor.red), 38 | self.contentView.mvn.cornerRadius.to(15), 39 | modal.view.mvn.frame.to(CGRect(x: 0, y: 0, width: modal.view.frame.size.width, height: modal.view.frame.size.height)), 40 | modal.view.mvn.alpha.from(0).to(0.8), 41 | modal.contentView.mvn.backgroundColor.to(UIColor.black), 42 | ]) 43 | 44 | modal.modalPresentationStyle = .custom 45 | let gesture = GestureAnimating(self.contentView, .bottom, self.view.mvn.halfSize) 46 | modal.transitioningDelegate = self.movin!.configureTransition(self.navigationController!, modal, GestureTransitioning(.present, gesture)).configureCompletion { [weak self] type, didComplete in 47 | print("didComplete : \(didComplete)") 48 | if type.isDismissing && didComplete { 49 | self?.setup() 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Proj/Demo/ModalViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModalViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class ModalViewController: UIViewController { 13 | 14 | @IBOutlet private(set) weak var contentView: UIView! 15 | 16 | deinit { 17 | print("denit ModalViewController") 18 | } 19 | 20 | @IBAction private func tapCloseButton() { 21 | self.dismiss(animated: true, completion: nil) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Proj/Demo/PresentTransitionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PresentTransitionViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class PresentTransitionViewController: UIViewController { 13 | 14 | @IBOutlet private weak var contentView: UIView! 15 | 16 | private var movin: Movin? 17 | 18 | @IBAction private func tapButton() { 19 | if #available(iOS 11.0, *) { 20 | self.movin = Movin(1.0, TimingCurve(curve: .easeInOut, dampingRatio: 0.8)) 21 | } else { 22 | self.movin = Movin(1.0) 23 | } 24 | 25 | let modal = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ModalViewController") as! ModalViewController 26 | modal.view.layoutIfNeeded() 27 | 28 | self.movin!.addAnimations([ 29 | self.contentView.mvn.alpha.to(0.5), 30 | self.contentView.mvn.frame.to(CGRect(x: 100, y: 150, width: 30, height: 30)), 31 | self.contentView.mvn.backgroundColor.to(UIColor.red), 32 | self.contentView.mvn.cornerRadius.to(15), 33 | modal.view.mvn.frame.to(CGRect(x: 0, y: 0, width: modal.view.frame.size.width, height: modal.view.frame.size.height)), 34 | modal.view.mvn.alpha.from(0).to(0.5), 35 | modal.contentView.mvn.backgroundColor.to(UIColor.black), 36 | ]) 37 | 38 | modal.modalPresentationStyle = .custom 39 | modal.transitioningDelegate = self.movin!.configureTransition(self.navigationController!, modal).configureCompletion { [weak self] type, didComplete in 40 | print("didComplete : \(didComplete)") 41 | if type.isDismissing && didComplete { 42 | self?.movin = nil 43 | } 44 | } 45 | self.present(modal, animated: true, completion: nil) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Proj/Demo/PushTransitionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PushTransitionViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class PushTransitionViewController: UIViewController { 13 | 14 | @IBOutlet private weak var contentView: UIView! 15 | 16 | private var movin: Movin? 17 | 18 | @IBAction private func tapButton() { 19 | self.movin = Movin(1.0) 20 | 21 | let detail = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController 22 | detail.view.layoutIfNeeded() 23 | 24 | self.movin!.addAnimations([ 25 | self.contentView.mvn.alpha.to(0.5), 26 | self.contentView.mvn.backgroundColor.to(UIColor.red), 27 | self.contentView.mvn.cornerRadius.to(15), 28 | detail.view.mvn.frame.to(CGRect(x: 0, y: 0, width: detail.view.frame.size.width, height: detail.view.frame.size.height)), 29 | detail.view.mvn.alpha.from(0).to(1), 30 | detail.contentView.mvn.backgroundColor.to(UIColor.black), 31 | ]) 32 | 33 | self.navigationController?.delegate = self.movin!.configureTransition(self, detail).configureCompletion { [weak self] type, didComplete in 34 | print("didComplete : \(didComplete)") 35 | if type.isDismissing && didComplete { 36 | self?.movin = nil 37 | } 38 | } 39 | self.navigationController?.pushViewController(detail, animated: true) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Proj/Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Demo 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/01. 6 | // Copyright © 2016 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Movin 11 | 12 | final class ViewController: UIViewController { 13 | 14 | @IBOutlet private weak var contentView: UIView! 15 | 16 | private var movin: Movin? 17 | 18 | private var originalFrame: CGRect = CGRect.zero 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | } 23 | 24 | override func viewDidAppear(_ animated: Bool) { 25 | super.viewDidAppear(animated) 26 | 27 | self.originalFrame = self.contentView.frame 28 | } 29 | 30 | @IBAction private func tapButton() { 31 | if #available(iOS 11.0, *) { 32 | self.movin = Movin(1.0, TimingCurve(curve: .easeInOut, dampingRatio: 0.8)) 33 | } else { 34 | self.movin = Movin(1.0) 35 | } 36 | 37 | self.movin!.addAnimations([ 38 | self.contentView.mvn.alpha.from(1.0).to(0.5), 39 | self.contentView.mvn.backgroundColor.from(.blue).to(.red), 40 | self.contentView.mvn.frame.from(self.originalFrame).to(CGRect(x: 100, y: 150, width: 30, height: 30)), 41 | self.contentView.mvn.cornerRadius.from(0).to(15), 42 | ]) 43 | 44 | self.movin!.startAnimation() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Proj/Movin.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 913F41B52111A97800950E56 /* Movin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 913F41B42111A97800950E56 /* Movin.swift */; }; 11 | 914D997A2111AD0D00FE7FED /* AnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914D99792111AD0D00FE7FED /* AnimatedTransitioning.swift */; }; 12 | 914D997C2111AF5200FE7FED /* Animations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914D997B2111AF5200FE7FED /* Animations.swift */; }; 13 | 914D997E211285EF00FE7FED /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 914D997D211285EF00FE7FED /* Extensions.swift */; }; 14 | 91B9EB3E1C59AE9600426490 /* Movin.h in Headers */ = {isa = PBXBuildFile; fileRef = 91B9EB361C59AC1900426490 /* Movin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 91D4563A2112BC94004A3F5E /* GestureAnimating.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456392112BC94004A3F5E /* GestureAnimating.swift */; }; 16 | 91D4563D2112BFD4004A3F5E /* InteractiveTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D4563C2112BFD4004A3F5E /* InteractiveTransitioning.swift */; }; 17 | 91D456472112C5FB004A3F5E /* Shorthands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456462112C5FB004A3F5E /* Shorthands.swift */; }; 18 | 91D4564A2112CC97004A3F5E /* TimingCurve.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D456492112CC97004A3F5E /* TimingCurve.swift */; }; 19 | 91D4564C2112D182004A3F5E /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91D4564B2112D182004A3F5E /* Transition.swift */; }; 20 | 91FD68C821199805008DD16A /* GestureTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91FD68C721199805008DD16A /* GestureTransitioning.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 913F41B42111A97800950E56 /* Movin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Movin.swift; sourceTree = ""; }; 25 | 914D99792111AD0D00FE7FED /* AnimatedTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnimatedTransitioning.swift; sourceTree = ""; }; 26 | 914D997B2111AF5200FE7FED /* Animations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animations.swift; sourceTree = ""; }; 27 | 914D997D211285EF00FE7FED /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 28 | 91B9EB1C1C59AB9700426490 /* Movin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Movin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 91B9EB361C59AC1900426490 /* Movin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Movin.h; sourceTree = ""; }; 30 | 91B9EB381C59AC1900426490 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 91D456392112BC94004A3F5E /* GestureAnimating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureAnimating.swift; sourceTree = ""; }; 32 | 91D4563C2112BFD4004A3F5E /* InteractiveTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveTransitioning.swift; sourceTree = ""; }; 33 | 91D456462112C5FB004A3F5E /* Shorthands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shorthands.swift; sourceTree = ""; }; 34 | 91D456492112CC97004A3F5E /* TimingCurve.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimingCurve.swift; sourceTree = ""; }; 35 | 91D4564B2112D182004A3F5E /* Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transition.swift; sourceTree = ""; }; 36 | 91FD68C721199805008DD16A /* GestureTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureTransitioning.swift; sourceTree = ""; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | 91B9EB181C59AB9700426490 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | ); 45 | runOnlyForDeploymentPostprocessing = 0; 46 | }; 47 | /* End PBXFrameworksBuildPhase section */ 48 | 49 | /* Begin PBXGroup section */ 50 | 91B9EB121C59AB9700426490 = { 51 | isa = PBXGroup; 52 | children = ( 53 | 91B9EB1E1C59AB9700426490 /* Sources */, 54 | 91B9EB1D1C59AB9700426490 /* Products */, 55 | ); 56 | sourceTree = ""; 57 | }; 58 | 91B9EB1D1C59AB9700426490 /* Products */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 91B9EB1C1C59AB9700426490 /* Movin.framework */, 62 | ); 63 | name = Products; 64 | sourceTree = ""; 65 | }; 66 | 91B9EB1E1C59AB9700426490 /* Sources */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 91B9EB361C59AC1900426490 /* Movin.h */, 70 | 91B9EB381C59AC1900426490 /* Info.plist */, 71 | 913F41B42111A97800950E56 /* Movin.swift */, 72 | 914D997B2111AF5200FE7FED /* Animations.swift */, 73 | 91D456492112CC97004A3F5E /* TimingCurve.swift */, 74 | 914D997D211285EF00FE7FED /* Extensions.swift */, 75 | 91D4564B2112D182004A3F5E /* Transition.swift */, 76 | 91D456392112BC94004A3F5E /* GestureAnimating.swift */, 77 | 914D99792111AD0D00FE7FED /* AnimatedTransitioning.swift */, 78 | 91FD68C721199805008DD16A /* GestureTransitioning.swift */, 79 | 91D4563C2112BFD4004A3F5E /* InteractiveTransitioning.swift */, 80 | 91D456462112C5FB004A3F5E /* Shorthands.swift */, 81 | ); 82 | name = Sources; 83 | path = ../Sources; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXHeadersBuildPhase section */ 89 | 91B9EB191C59AB9700426490 /* Headers */ = { 90 | isa = PBXHeadersBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | 91B9EB3E1C59AE9600426490 /* Movin.h in Headers */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | /* End PBXHeadersBuildPhase section */ 98 | 99 | /* Begin PBXNativeTarget section */ 100 | 91B9EB1B1C59AB9700426490 /* Movin */ = { 101 | isa = PBXNativeTarget; 102 | buildConfigurationList = 91B9EB301C59AB9700426490 /* Build configuration list for PBXNativeTarget "Movin" */; 103 | buildPhases = ( 104 | 91B9EB171C59AB9700426490 /* Sources */, 105 | 91B9EB181C59AB9700426490 /* Frameworks */, 106 | 91B9EB191C59AB9700426490 /* Headers */, 107 | 91B9EB1A1C59AB9700426490 /* Resources */, 108 | ); 109 | buildRules = ( 110 | ); 111 | dependencies = ( 112 | ); 113 | name = Movin; 114 | productName = Chain; 115 | productReference = 91B9EB1C1C59AB9700426490 /* Movin.framework */; 116 | productType = "com.apple.product-type.framework"; 117 | }; 118 | /* End PBXNativeTarget section */ 119 | 120 | /* Begin PBXProject section */ 121 | 91B9EB131C59AB9700426490 /* Project object */ = { 122 | isa = PBXProject; 123 | attributes = { 124 | LastSwiftUpdateCheck = 0720; 125 | LastUpgradeCheck = 1020; 126 | ORGANIZATIONNAME = xxxAIRINxxx; 127 | TargetAttributes = { 128 | 91B9EB1B1C59AB9700426490 = { 129 | CreatedOnToolsVersion = 7.2; 130 | DevelopmentTeam = P599PJHMNF; 131 | LastSwiftMigration = 1020; 132 | ProvisioningStyle = Automatic; 133 | }; 134 | }; 135 | }; 136 | buildConfigurationList = 91B9EB161C59AB9700426490 /* Build configuration list for PBXProject "Movin" */; 137 | compatibilityVersion = "Xcode 3.2"; 138 | developmentRegion = en; 139 | hasScannedForEncodings = 0; 140 | knownRegions = ( 141 | en, 142 | Base, 143 | ); 144 | mainGroup = 91B9EB121C59AB9700426490; 145 | productRefGroup = 91B9EB1D1C59AB9700426490 /* Products */; 146 | projectDirPath = ""; 147 | projectRoot = ""; 148 | targets = ( 149 | 91B9EB1B1C59AB9700426490 /* Movin */, 150 | ); 151 | }; 152 | /* End PBXProject section */ 153 | 154 | /* Begin PBXResourcesBuildPhase section */ 155 | 91B9EB1A1C59AB9700426490 /* Resources */ = { 156 | isa = PBXResourcesBuildPhase; 157 | buildActionMask = 2147483647; 158 | files = ( 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXResourcesBuildPhase section */ 163 | 164 | /* Begin PBXSourcesBuildPhase section */ 165 | 91B9EB171C59AB9700426490 /* Sources */ = { 166 | isa = PBXSourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 91D4564C2112D182004A3F5E /* Transition.swift in Sources */, 170 | 91D456472112C5FB004A3F5E /* Shorthands.swift in Sources */, 171 | 914D997A2111AD0D00FE7FED /* AnimatedTransitioning.swift in Sources */, 172 | 91D4563A2112BC94004A3F5E /* GestureAnimating.swift in Sources */, 173 | 91D4563D2112BFD4004A3F5E /* InteractiveTransitioning.swift in Sources */, 174 | 914D997C2111AF5200FE7FED /* Animations.swift in Sources */, 175 | 91D4564A2112CC97004A3F5E /* TimingCurve.swift in Sources */, 176 | 913F41B52111A97800950E56 /* Movin.swift in Sources */, 177 | 914D997E211285EF00FE7FED /* Extensions.swift in Sources */, 178 | 91FD68C821199805008DD16A /* GestureTransitioning.swift in Sources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXSourcesBuildPhase section */ 183 | 184 | /* Begin XCBuildConfiguration section */ 185 | 91B9EB2E1C59AB9700426490 /* Debug */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 191 | CLANG_CXX_LIBRARY = "libc++"; 192 | CLANG_ENABLE_MODULES = YES; 193 | CLANG_ENABLE_OBJC_ARC = YES; 194 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 195 | CLANG_WARN_BOOL_CONVERSION = YES; 196 | CLANG_WARN_COMMA = YES; 197 | CLANG_WARN_CONSTANT_CONVERSION = YES; 198 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 199 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 200 | CLANG_WARN_EMPTY_BODY = YES; 201 | CLANG_WARN_ENUM_CONVERSION = YES; 202 | CLANG_WARN_INFINITE_RECURSION = YES; 203 | CLANG_WARN_INT_CONVERSION = YES; 204 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 206 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 207 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 208 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 209 | CLANG_WARN_STRICT_PROTOTYPES = YES; 210 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 211 | CLANG_WARN_UNREACHABLE_CODE = YES; 212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 213 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 214 | COPY_PHASE_STRIP = NO; 215 | CURRENT_PROJECT_VERSION = 1; 216 | DEBUG_INFORMATION_FORMAT = dwarf; 217 | ENABLE_STRICT_OBJC_MSGSEND = YES; 218 | ENABLE_TESTABILITY = YES; 219 | GCC_C_LANGUAGE_STANDARD = gnu99; 220 | GCC_DYNAMIC_NO_PIC = NO; 221 | GCC_NO_COMMON_BLOCKS = YES; 222 | GCC_OPTIMIZATION_LEVEL = 0; 223 | GCC_PREPROCESSOR_DEFINITIONS = ( 224 | "DEBUG=1", 225 | "$(inherited)", 226 | ); 227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 229 | GCC_WARN_UNDECLARED_SELECTOR = YES; 230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 231 | GCC_WARN_UNUSED_FUNCTION = YES; 232 | GCC_WARN_UNUSED_VARIABLE = YES; 233 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 234 | MTL_ENABLE_DEBUG_INFO = YES; 235 | ONLY_ACTIVE_ARCH = YES; 236 | SDKROOT = iphoneos; 237 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 238 | SWIFT_VERSION = 5.0; 239 | TARGETED_DEVICE_FAMILY = "1,2"; 240 | VERSIONING_SYSTEM = "apple-generic"; 241 | VERSION_INFO_PREFIX = ""; 242 | }; 243 | name = Debug; 244 | }; 245 | 91B9EB2F1C59AB9700426490 /* Release */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ALWAYS_SEARCH_USER_PATHS = NO; 249 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 251 | CLANG_CXX_LIBRARY = "libc++"; 252 | CLANG_ENABLE_MODULES = YES; 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_COMMA = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_EMPTY_BODY = YES; 261 | CLANG_WARN_ENUM_CONVERSION = YES; 262 | CLANG_WARN_INFINITE_RECURSION = YES; 263 | CLANG_WARN_INT_CONVERSION = YES; 264 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 266 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 269 | CLANG_WARN_STRICT_PROTOTYPES = YES; 270 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 271 | CLANG_WARN_UNREACHABLE_CODE = YES; 272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 273 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 274 | COPY_PHASE_STRIP = NO; 275 | CURRENT_PROJECT_VERSION = 1; 276 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 277 | ENABLE_NS_ASSERTIONS = NO; 278 | ENABLE_STRICT_OBJC_MSGSEND = YES; 279 | GCC_C_LANGUAGE_STANDARD = gnu99; 280 | GCC_NO_COMMON_BLOCKS = YES; 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 288 | MTL_ENABLE_DEBUG_INFO = NO; 289 | SDKROOT = iphoneos; 290 | SWIFT_VERSION = 5.0; 291 | TARGETED_DEVICE_FAMILY = "1,2"; 292 | VALIDATE_PRODUCT = YES; 293 | VERSIONING_SYSTEM = "apple-generic"; 294 | VERSION_INFO_PREFIX = ""; 295 | }; 296 | name = Release; 297 | }; 298 | 91B9EB311C59AB9700426490 /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | CLANG_ENABLE_MODULES = YES; 302 | CODE_SIGN_IDENTITY = "iPhone Developer"; 303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 304 | DEFINES_MODULE = YES; 305 | DEVELOPMENT_TEAM = P599PJHMNF; 306 | DYLIB_COMPATIBILITY_VERSION = 1; 307 | DYLIB_CURRENT_VERSION = 1; 308 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 309 | INFOPLIST_FILE = "$(SRCROOT)/../Sources/Info.plist"; 310 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 311 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 312 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 313 | PRODUCT_BUNDLE_IDENTIFIER = xxxAIRINxxx.Movin; 314 | PRODUCT_NAME = Movin; 315 | SKIP_INSTALL = YES; 316 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 317 | SWIFT_VERSION = 5.0; 318 | }; 319 | name = Debug; 320 | }; 321 | 91B9EB321C59AB9700426490 /* Release */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | CLANG_ENABLE_MODULES = YES; 325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 326 | DEFINES_MODULE = YES; 327 | DEVELOPMENT_TEAM = P599PJHMNF; 328 | DYLIB_COMPATIBILITY_VERSION = 1; 329 | DYLIB_CURRENT_VERSION = 1; 330 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 331 | INFOPLIST_FILE = "$(SRCROOT)/../Sources/Info.plist"; 332 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 333 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 334 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 335 | PRODUCT_BUNDLE_IDENTIFIER = xxxAIRINxxx.Movin; 336 | PRODUCT_NAME = Movin; 337 | SKIP_INSTALL = YES; 338 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 339 | SWIFT_VERSION = 5.0; 340 | }; 341 | name = Release; 342 | }; 343 | /* End XCBuildConfiguration section */ 344 | 345 | /* Begin XCConfigurationList section */ 346 | 91B9EB161C59AB9700426490 /* Build configuration list for PBXProject "Movin" */ = { 347 | isa = XCConfigurationList; 348 | buildConfigurations = ( 349 | 91B9EB2E1C59AB9700426490 /* Debug */, 350 | 91B9EB2F1C59AB9700426490 /* Release */, 351 | ); 352 | defaultConfigurationIsVisible = 0; 353 | defaultConfigurationName = Release; 354 | }; 355 | 91B9EB301C59AB9700426490 /* Build configuration list for PBXNativeTarget "Movin" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | 91B9EB311C59AB9700426490 /* Debug */, 359 | 91B9EB321C59AB9700426490 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | /* End XCConfigurationList section */ 365 | }; 366 | rootObject = 91B9EB131C59AB9700426490 /* Project object */; 367 | } 368 | -------------------------------------------------------------------------------- /Proj/Movin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Proj/Movin.xcodeproj/xcshareddata/xcschemes/Movin.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 72 | 73 | 79 | 80 | 81 | 82 | 84 | 85 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Proj/Movin.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Proj/Movin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Proj/Movin.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Proj/MovinPlayground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import XCPlayground 3 | import PlaygroundSupport 4 | 5 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 580)) 6 | view.backgroundColor = UIColor.white 7 | XCPShowView(identifier: "preview", view: view) 8 | 9 | let v = UIView(frame: CGRect(x: 0,y: 0,width: 44,height: 44)) 10 | v.backgroundColor = UIColor.red 11 | view.addSubview(v) 12 | 13 | UIView.animate(withDuration: 0.5) { () -> Void in 14 | v.center = view.center 15 | } 16 | -------------------------------------------------------------------------------- /Proj/MovinPlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Movin 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/Movin.svg?style=flat)](http://cocoadocs.org/docsets/Movin) 4 | [![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg?style=flat)](https://developer.apple.com/swift/) 5 | [![Platforms iOS](https://img.shields.io/badge/Platforms-iOS-lightgray.svg?style=flat)](https://developer.apple.com/swift/) 6 | [![Xcode 10.2](https://img.shields.io/badge/Xcode-10.2-blue.svg?style=flat)](https://developer.apple.com/swift/) 7 | 8 | UIViewPropertyAnimator based View Transition Animator 9 | 10 | 11 | # Document is Soon... 12 | 13 | 14 | ### Display Movin Debug Print 15 | 16 | ``` swift 17 | 18 | Movin.isDebugPrintEnabled = true 19 | 20 | ``` 21 | 22 | ## Showcase 23 | 24 | ![music](Images/music.gif "music") 25 | 26 | [MusicAppTransition](https://github.com/xxxAIRINxxx/MusicAppTransition) 27 | 28 | ## Requirements 29 | 30 | * Xcode 10+ 31 | 32 | | | OS | Swift | 33 | |------------|------------------|--------------| 34 | | **v1.0.x** | iOS 10+ | 4.1 | 35 | | **v1.1.x** | iOS 10+ | 4.2 | 36 | | **v1.2.x** | iOS 10+ | 5.0 | 37 | 38 | ## Installation 39 | 40 | #### CocoaPods 41 | 42 | You can use [CocoaPods](http://cocoapods.org/) to install `Movin` by adding it to your `Podfile`: 43 | 44 | ``` ruby 45 | 46 | use_frameworks! 47 | pod 'Movin' 48 | 49 | ``` 50 | 51 | To get the full benefits import `Movin` wherever you import UIKit 52 | 53 | ``` swift 54 | 55 | import UIKit 56 | import Movin 57 | 58 | ``` 59 | 60 | #### Carthage 61 | 62 | You can use [Carthage](https://github.com/Carthage/Carthage) to install `Movin` by adding it to your `Cartfile`: 63 | 64 | ``` 65 | 66 | github "xxxAIRINxxx/Movin" 67 | 68 | ``` 69 | 70 | To get the full benefits import `Movin` wherever you import UIKit 71 | 72 | ``` swift 73 | 74 | import UIKit 75 | import Movin 76 | 77 | ``` 78 | #### Manually 79 | 80 | 1. Download and drop ```/Sources``` folder in your project. 81 | 2. Congratulations! 82 | 83 | ## License 84 | 85 | MIT license. See the LICENSE file for more info. 86 | -------------------------------------------------------------------------------- /Sources/AnimatedTransitioning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedTransitioning.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/01. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public final class AnimatedTransitioning : NSObject { 13 | 14 | public fileprivate(set) weak var transition: Transition! 15 | public let type: TransitionType 16 | 17 | deinit { 18 | Movin.dp("AnimatedTransitioning - deinit") 19 | } 20 | 21 | public init( _ transition: Transition, _ type: TransitionType) { 22 | self.transition = transition 23 | self.type = type 24 | 25 | super.init() 26 | } 27 | } 28 | 29 | extension AnimatedTransitioning : UIViewControllerAnimatedTransitioning { 30 | 31 | public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 32 | Movin.dp("AnimatedTransitioning - transitionDuration") 33 | return self.transition.movin.duration 34 | } 35 | 36 | public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 37 | Movin.dp("AnimatedTransitioning - animateTransition") 38 | self.transition.prepareTransition(self.type, transitionContext) 39 | let type = self.type 40 | self.transition.movin.animator.addCompletion { [weak self] position in 41 | switch position { 42 | case .current: 43 | break 44 | default: 45 | self?.transition.finishTransition(type, true, transitionContext.containerView) 46 | transitionContext.completeTransition(true) 47 | } 48 | } 49 | 50 | self.interruptibleAnimator(using: transitionContext).startAnimation() 51 | } 52 | 53 | public func interruptibleAnimator(using transitionContext: UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating { 54 | 55 | return self.transition.movin.animator 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Animations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Animations.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/01. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public struct AnimationDirection { 13 | 14 | public let duration: TimeInterval 15 | public let isFoward: Bool 16 | 17 | public init(_ duration: TimeInterval, _ isFoward: Bool) { 18 | self.duration = duration 19 | self.isFoward = isFoward 20 | } 21 | } 22 | 23 | public protocol AnimationCompatible: class { 24 | 25 | var delayFactor: CGFloat { get set } 26 | 27 | func beforeAnimation() 28 | func aninmate(_ animationDirection: AnimationDirection) 29 | 30 | // optional 31 | func finishAnimation(_ isFoward: Bool, _ didComplete: Bool) 32 | 33 | // optional 34 | func interactiveAnimate(_ fractionComplete: CGFloat) 35 | func finishInteractiveAnimation(_ interactiveTransitioning: InteractiveTransitioning) 36 | } 37 | 38 | public extension AnimationCompatible { 39 | 40 | @discardableResult func delay(_ v: CGFloat) -> Self { 41 | self.delayFactor = v 42 | return self 43 | } 44 | 45 | func interactiveAnimate(_ fractionComplete: CGFloat) {} 46 | 47 | func finishInteractiveAnimation(_ interactiveTransitioning: InteractiveTransitioning) {} 48 | } 49 | 50 | public protocol ValueAnimationCompatible: AnimationCompatible { 51 | 52 | associatedtype Value 53 | 54 | var fromValue: Value { get set } 55 | var toValue: Value { get set } 56 | var currentValue: Value { get set } 57 | } 58 | 59 | public extension ValueAnimationCompatible { 60 | 61 | @discardableResult func from(_ v: Value) -> Self { 62 | self.fromValue = v 63 | return self 64 | } 65 | 66 | @discardableResult func to(_ v: Value) -> Self { 67 | self.toValue = v 68 | return self 69 | } 70 | 71 | func beforeAnimation() { 72 | self.currentValue = self.fromValue 73 | } 74 | 75 | func aninmate(_ animationDirection: AnimationDirection) { 76 | self.currentValue = self.toValue 77 | } 78 | 79 | func finishAnimation(_ isFoward: Bool, _ didComplete: Bool) { 80 | if isFoward { 81 | self.currentValue = didComplete ? self.toValue : self.fromValue 82 | } else { 83 | self.currentValue = didComplete ? self.fromValue : self.toValue 84 | } 85 | } 86 | } 87 | 88 | public final class AlphaAnimation : ValueAnimationCompatible { 89 | 90 | public typealias Value = CGFloat 91 | 92 | public let view: UIView 93 | 94 | public var delayFactor: CGFloat = 0 95 | public var fromValue: Value 96 | public var toValue: Value = 0 97 | public var currentValue: Value { didSet { self.view.alpha = self.currentValue } } 98 | 99 | deinit { 100 | Movin.dp("AlphaAnimation - deinit") 101 | } 102 | 103 | public init(_ view: UIView) { 104 | self.view = view 105 | self.fromValue = view.alpha 106 | self.currentValue = self.fromValue 107 | } 108 | } 109 | 110 | public final class BackgroundColorAnimation : ValueAnimationCompatible { 111 | 112 | public typealias Value = UIColor 113 | 114 | public let view: UIView 115 | 116 | public var delayFactor: CGFloat = 0 117 | public var fromValue: Value 118 | public var toValue: Value 119 | public var currentValue: Value { didSet { self.view.backgroundColor = self.currentValue } } 120 | 121 | deinit { 122 | Movin.dp("BackgroundColorAnimation - deinit") 123 | } 124 | 125 | public init(_ view: UIView) { 126 | self.view = view 127 | 128 | self.fromValue = view.backgroundColor ?? .white 129 | self.toValue = view.backgroundColor ?? .white 130 | self.currentValue = self.fromValue 131 | } 132 | } 133 | 134 | public final class FrameAnimation : ValueAnimationCompatible { 135 | 136 | public typealias Value = CGRect 137 | 138 | public let view: UIView 139 | 140 | public var delayFactor: CGFloat = 0 141 | public var fromValue: Value 142 | public var toValue: Value 143 | public var currentValue: Value { didSet { self.view.frame = self.currentValue } } 144 | 145 | deinit { 146 | Movin.dp("FrameAnimation - deinit") 147 | } 148 | 149 | public init(_ view: UIView) { 150 | self.view = view 151 | 152 | self.fromValue = view.frame 153 | self.toValue = view.frame 154 | self.currentValue = self.fromValue 155 | } 156 | } 157 | 158 | public final class PointAnimation : ValueAnimationCompatible { 159 | 160 | public typealias Value = CGPoint 161 | 162 | public let view: UIView 163 | 164 | public var delayFactor: CGFloat = 0 165 | public var fromValue: Value 166 | public var toValue: Value 167 | public var currentValue: Value { didSet { self.view.frame.origin = self.currentValue } } 168 | 169 | deinit { 170 | Movin.dp("PointAnimation - deinit") 171 | } 172 | 173 | public init(_ view: UIView) { 174 | self.view = view 175 | 176 | self.fromValue = view.frame.origin 177 | self.toValue = view.frame.origin 178 | self.currentValue = self.fromValue 179 | } 180 | } 181 | 182 | public final class SizeAnimation : ValueAnimationCompatible { 183 | 184 | public typealias Value = CGSize 185 | 186 | public let view: UIView 187 | 188 | public var delayFactor: CGFloat = 0 189 | public var fromValue: Value 190 | public var toValue: Value 191 | public var currentValue: Value { didSet { self.view.frame.size = self.currentValue } } 192 | 193 | deinit { 194 | Movin.dp("SizeAnimation - deinit") 195 | } 196 | 197 | public init(_ view: UIView) { 198 | self.view = view 199 | 200 | self.fromValue = view.frame.size 201 | self.toValue = view.frame.size 202 | self.currentValue = self.fromValue 203 | } 204 | } 205 | 206 | public final class CornerRadiusAnimation : ValueAnimationCompatible { 207 | 208 | public typealias Value = CGFloat 209 | 210 | public let view: UIView 211 | 212 | public var delayFactor: CGFloat = 0 213 | public var fromValue: Value 214 | public var toValue: Value 215 | public var currentValue: Value { didSet { self.view.layer.cornerRadius = self.currentValue } } 216 | 217 | deinit { 218 | Movin.dp("CornerRadiusAnimation - deinit") 219 | } 220 | 221 | public init(_ view: UIView) { 222 | self.view = view 223 | 224 | self.fromValue = view.layer.cornerRadius 225 | self.toValue = view.layer.cornerRadius 226 | self.currentValue = self.fromValue 227 | self.view.clipsToBounds = true 228 | } 229 | 230 | public func aninmate(_ animationDirection: AnimationDirection) { 231 | if #available(iOS 11.0, *) { 232 | self.currentValue = self.toValue 233 | } else { 234 | let animation = CABasicAnimation(keyPath: "cornerRadius") 235 | animation.duration = animationDirection.duration 236 | animation.fromValue = animationDirection.isFoward ? self.fromValue : self.toValue 237 | animation.toValue = animationDirection.isFoward ? self.toValue : self.fromValue 238 | animation.isRemovedOnCompletion = true 239 | self.view.layer.add(animation, forKey: "cornerRadius") 240 | self.view.layer.cornerRadius = animationDirection.isFoward ? self.toValue : self.fromValue 241 | } 242 | } 243 | 244 | public func interactiveAnimate(_ fractionComplete: CGFloat) { 245 | if #available(iOS 11.0, *) { 246 | } else { 247 | self.currentValue = self.toValue * fractionComplete 248 | let animation = CABasicAnimation(keyPath: "cornerRadius") 249 | animation.duration = 0.01 250 | animation.fromValue = self.currentValue 251 | animation.toValue = self.currentValue 252 | self.view.layer.add(animation, forKey: "cornerRadius") 253 | } 254 | } 255 | 256 | public func finishInteractiveAnimation(_ interactiveTransitioning: InteractiveTransitioning) { 257 | if #available(iOS 11.0, *) { 258 | } else { 259 | let duration = interactiveTransitioning.duration * (1.0 - interactiveTransitioning.transition.movin.animator.fractionComplete) 260 | let animation = CABasicAnimation(keyPath: "cornerRadius") 261 | animation.duration = duration.toDouble 262 | animation.fromValue = self.currentValue 263 | if interactiveTransitioning.type.isPresenting { 264 | animation.toValue = interactiveTransitioning.isCompleted ? self.toValue : self.fromValue 265 | } else { 266 | animation.toValue = interactiveTransitioning.isCompleted ? self.fromValue : self.toValue 267 | } 268 | animation.isRemovedOnCompletion = true 269 | self.view.layer.add(animation, forKey: "cornerRadius") 270 | 271 | if interactiveTransitioning.type.isPresenting { 272 | self.view.layer.cornerRadius = interactiveTransitioning.isCompleted ? self.toValue : self.fromValue 273 | } else { 274 | self.view.layer.cornerRadius = interactiveTransitioning.isCompleted ? self.fromValue : self.toValue 275 | } 276 | } 277 | } 278 | } 279 | 280 | public final class TransformAnimation : ValueAnimationCompatible { 281 | 282 | public typealias Value = CGAffineTransform 283 | 284 | public let view: UIView 285 | 286 | public var delayFactor: CGFloat = 0 287 | public var fromValue: Value 288 | public var toValue: Value 289 | public var currentValue: Value { didSet { self.view.transform = self.currentValue } } 290 | 291 | deinit { 292 | Movin.dp("TransformAnimation - deinit") 293 | } 294 | 295 | public init(_ view: UIView) { 296 | self.view = view 297 | 298 | self.fromValue = view.transform 299 | self.toValue = view.transform 300 | self.currentValue = self.fromValue 301 | } 302 | } 303 | 304 | public class CustomAnimation : AnimationCompatible { 305 | 306 | public let view: UIView 307 | 308 | public var delayFactor: CGFloat = 0 309 | 310 | private var animation: (UIView) -> Swift.Void 311 | private var before: ((UIView) -> Swift.Void)? 312 | private var finish: ((Bool, Bool) -> Swift.Void)? 313 | 314 | deinit { 315 | Movin.dp("CustomAnimation - deinit") 316 | } 317 | 318 | public init(_ view: UIView, _ animation: @escaping (UIView) -> Swift.Void) { 319 | self.view = view 320 | self.animation = animation 321 | } 322 | 323 | @discardableResult public func configureBefore(_ before: ((UIView) -> Swift.Void)? = nil) -> CustomAnimation { 324 | self.before = before 325 | return self 326 | } 327 | 328 | @discardableResult public func configureFinish(_ finish: ((Bool, Bool) -> Swift.Void)? = nil) -> CustomAnimation { 329 | self.finish = finish 330 | return self 331 | } 332 | 333 | public func beforeAnimation() { 334 | self.before?(self.view) 335 | } 336 | 337 | public func aninmate(_ animationDirection: AnimationDirection) { 338 | self.animation(self.view) 339 | } 340 | 341 | public func finishAnimation(_ isFoward: Bool, _ didComplete: Bool) { 342 | self.finish?(isFoward, didComplete) 343 | } 344 | } 345 | 346 | // WIP 347 | 348 | //public class CustomTimingAnimation : AnimationCompatible { 349 | // 350 | // public let view: UIView 351 | // public let duration: TimeInterval 352 | // 353 | // public var delayFactor: CGFloat = 0 354 | // 355 | // private var before: ((UIView) -> Swift.Void)? 356 | // private var finish: ((Bool, Bool) -> Swift.Void)? 357 | // 358 | // deinit { 359 | // Movin.dp("CustomAnimation - deinit") 360 | // } 361 | // 362 | // public init(_ view: UIView, _ duration: TimeInterval) { 363 | // self.view = view 364 | // self.duration = duration 365 | // } 366 | // 367 | // @discardableResult public func configureBefore(_ before: ((UIView) -> Swift.Void)? = nil) -> CustomTimingAnimation { 368 | // self.before = before 369 | // return self 370 | // } 371 | // 372 | // @discardableResult public func configureFinish(_ finish: ((Bool, Bool) -> Swift.Void)? = nil) -> CustomTimingAnimation { 373 | // self.finish = finish 374 | // return self 375 | // } 376 | // 377 | // public func beforeAnimation() { 378 | // self.before?(self.view) 379 | // } 380 | // 381 | // public func aninmate(_ animationDirection: AnimationDirection) { 382 | // 383 | // } 384 | // 385 | // public func finishAnimation(_ isFoward: Bool, _ didComplete: Bool) { 386 | // self.finish?(isFoward, didComplete) 387 | // } 388 | // 389 | // public func interactiveAnimate(_ fractionComplete: CGFloat) { 390 | // } 391 | //} 392 | -------------------------------------------------------------------------------- /Sources/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension Double { 13 | 14 | var toCGFloat: CGFloat { return CGFloat(self) } 15 | } 16 | 17 | extension CGFloat { 18 | 19 | var toDouble: Double { return Double(self) } 20 | } 21 | 22 | extension UIViewController { 23 | 24 | var isOverContext: Bool { 25 | switch self.modalPresentationStyle { 26 | case .currentContext, 27 | .overFullScreen, 28 | .overCurrentContext, 29 | .custom: 30 | return true 31 | default: 32 | return false 33 | } 34 | } 35 | } 36 | 37 | func sigmoid(x: Double) -> Double { 38 | return 1.0 / (1.0 + exp(-x)) 39 | } 40 | 41 | func sigmoidGradient(x: Double) -> Double { 42 | return (1.0 - sigmoid(x: x)) * sigmoid(x: x) 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Sources/GestureAnimating.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GestureAnimating.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public enum GestureDirectionType { 13 | case top 14 | case bottom 15 | case left 16 | case right 17 | case none(UIView) 18 | 19 | var canAutoStartAnimation: Bool { 20 | switch self { 21 | case .none: return false 22 | default: return true 23 | } 24 | } 25 | } 26 | 27 | public class GestureAnimating: NSObject { 28 | 29 | var updateGestureHandler: ((CGFloat) -> Void)? 30 | var updateGestureStateHandler: ((UIGestureRecognizer.State) -> Void)? 31 | 32 | public fileprivate(set) weak var view: UIView! 33 | public let direction: GestureDirectionType 34 | public let range: CGSize 35 | 36 | public var panCompletionThresholdRatio: CGFloat = 0.8 37 | public var smoothness: CGFloat = 1.0 38 | 39 | fileprivate(set) var currentProgress: CGFloat = 0.0 40 | fileprivate(set) var isCompleted: Bool = false 41 | 42 | fileprivate(set) var gesture: UIPanGestureRecognizer? 43 | 44 | deinit { 45 | Movin.dp("GestureAnimating - deinit") 46 | self.unregisterGesture() 47 | } 48 | 49 | public init(_ view: UIView, _ direction: GestureDirectionType, _ range: CGSize) { 50 | self.view = view 51 | self.direction = direction 52 | self.range = range 53 | 54 | super.init() 55 | 56 | self.registerGesture(view) 57 | } 58 | 59 | fileprivate func registerGesture(_ view: UIView) { 60 | Movin.dp("GestureAnimating - registerGesture") 61 | self.gesture = UIPanGestureRecognizer(target: self, action: #selector(handleGesture(_:))) 62 | self.gesture?.maximumNumberOfTouches = 1 63 | self.gesture?.delegate = self 64 | view.addGestureRecognizer(self.gesture!) 65 | } 66 | 67 | func unregisterGesture() { 68 | Movin.dp("GestureAnimating - unregisterGesture") 69 | guard let g = self.gesture else { return } 70 | g.view?.removeGestureRecognizer(g) 71 | self.gesture = nil 72 | } 73 | 74 | @objc fileprivate func handleGesture(_ recognizer: UIPanGestureRecognizer) { 75 | let translation = recognizer.translation(in: self.view) 76 | 77 | switch self.direction { 78 | case .top: 79 | let translatedCenterY = translation.y * -1.0 * self.smoothness 80 | self.currentProgress = translatedCenterY / self.range.height 81 | case .bottom: 82 | let translatedCenterY = translation.y * self.smoothness 83 | self.currentProgress = translatedCenterY / self.range.height 84 | case .left: 85 | let translatedCenterX = translation.x * -1.0 * self.smoothness 86 | self.currentProgress = translatedCenterX / self.range.width 87 | case .right: 88 | let translatedCenterX = translation.x * self.smoothness 89 | self.currentProgress = translatedCenterX / self.range.width 90 | case .none(let parentView): 91 | self.view.center = recognizer.location(in: parentView) 92 | let x = translation.x / self.range.width 93 | let y = translation.y / self.range.height 94 | self.currentProgress = max(x, y) 95 | } 96 | 97 | Movin.dp(self.currentProgress, key: "GestureAnimating currentProgress : ") 98 | 99 | self.isCompleted = self.currentProgress >= self.panCompletionThresholdRatio 100 | self.updateGestureHandler?(self.currentProgress) 101 | self.updateGestureStateHandler?(recognizer.state) 102 | } 103 | } 104 | 105 | // MARK: - UIGestureRecognizerDelegate 106 | 107 | extension GestureAnimating : UIGestureRecognizerDelegate { 108 | 109 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 110 | Movin.dp("GestureAnimating - shouldRecognizeSimultaneouslyWith") 111 | guard let g = self.gesture else { return false } 112 | guard g.view is UIScrollView else { return false } 113 | return true 114 | } 115 | 116 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy 117 | otherGestureRecognizer: UIGestureRecognizer) -> Bool { 118 | Movin.dp("GestureAnimating - shouldBeRequiredToFailBy") 119 | return false 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Sources/GestureTransitioning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GestureTransitioning.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public final class GestureTransitioning { 13 | 14 | let type: TransitionType 15 | let presentingGesture: GestureAnimating? 16 | let dismissingGesture: GestureAnimating? 17 | 18 | deinit { 19 | Movin.dp("GestureTransitioning - deinit") 20 | } 21 | 22 | public init(_ type: TransitionType, _ presentingGesture: GestureAnimating?, _ dismissingGesture: GestureAnimating? = nil) { 23 | self.type = type 24 | self.presentingGesture = presentingGesture 25 | self.dismissingGesture = dismissingGesture 26 | } 27 | 28 | func currentType() -> TransitionType { 29 | Movin.dp("GestureTransitioning - currentType") 30 | if self.presentingGesture?.gesture == nil { return self.type.reversedType } 31 | return self.type 32 | } 33 | 34 | func gesture(_ type: TransitionType) -> GestureAnimating? { 35 | Movin.dp("Transition - gesture type: \(type)") 36 | return type.isPresenting ? self.presentingGesture : self.dismissingGesture 37 | } 38 | 39 | func hasGesture(_ type: TransitionType) -> Bool { 40 | Movin.dp("Transition - hasGesture type: \(type)") 41 | if type.isPresenting { return self.presentingGesture?.gesture != nil } 42 | return self.dismissingGesture?.gesture != nil 43 | } 44 | 45 | func finishTransition(_ type: TransitionType, _ didComplete: Bool) { 46 | Movin.dp("Transition - finishTransition type: \(type), didComplete: \(didComplete)") 47 | if !didComplete { return } 48 | self.gesture(type)?.unregisterGesture() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/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.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/InteractiveTransitioning.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InteractiveTransitioning.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public final class InteractiveTransitioning : UIPercentDrivenInteractiveTransition { 13 | 14 | weak fileprivate(set) var transition: Transition! 15 | let type: TransitionType 16 | 17 | private(set) var isCompleted: Bool = false 18 | private var containerView: UIView? 19 | 20 | deinit { 21 | Movin.dp("InteractiveTransitioning - deinit") 22 | } 23 | 24 | public init(_ transition: Transition, _ type: TransitionType) { 25 | self.type = type 26 | self.transition = transition 27 | 28 | super.init() 29 | 30 | self.timingCurve = transition.movin.timingParameters 31 | } 32 | 33 | public override var duration: CGFloat { return self.transition.movin.duration.toCGFloat } 34 | 35 | public override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) { 36 | Movin.dp("InteractiveTransitioning - startInteractiveTransition") 37 | self.containerView = transitionContext.containerView 38 | let type = self.type 39 | self.transition.prepareTransition(type, transitionContext) 40 | self.transition.movin.animator.addCompletion { [weak self] position in 41 | let isCompleted = self?.isCompleted ?? false 42 | self?.transition.finishTransition(type, isCompleted, transitionContext.containerView) 43 | transitionContext.completeTransition(isCompleted) 44 | } 45 | 46 | self.transition.movin.animator.startAnimation() 47 | self.transition.movin.animator.pauseAnimation() 48 | } 49 | 50 | public override func update(_ percentComplete: CGFloat) { 51 | super.update(percentComplete) 52 | 53 | self.transition.movin.animator.fractionComplete = percentComplete 54 | } 55 | 56 | public override func finish() { 57 | Movin.dp("InteractiveTransitioning - finish") 58 | super.finish() 59 | 60 | self.isCompleted = true 61 | self.transition.movin.end(self.type.isPresenting) 62 | self.transition.movin.finishInteractiveAnimation(self) 63 | } 64 | 65 | public override func cancel() { 66 | Movin.dp("InteractiveTransitioning - cancel") 67 | super.cancel() 68 | 69 | self.isCompleted = false 70 | self.transition.movin.cancel(self.type.isPresenting) 71 | self.transition.movin.finishInteractiveAnimation(self) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/Movin.h: -------------------------------------------------------------------------------- 1 | // 2 | // Movin.h 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/07/31. 6 | // Copyright © 2016 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Movin. 12 | FOUNDATION_EXPORT double MovinVersionNumber; 13 | 14 | //! Project version string for Movin. 15 | FOUNDATION_EXPORT const unsigned char MovinVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/Movin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Movin.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/01. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public enum MovinMode { 13 | case auto 14 | case interactive(GestureAnimating) 15 | } 16 | 17 | public final class Movin { 18 | 19 | public let duration: TimeInterval 20 | 21 | let timingParameters: UITimingCurveProvider 22 | let animator: UIViewPropertyAnimator 23 | private var animations: [AnimationCompatible] = [] 24 | 25 | private var transition: Transition? 26 | 27 | deinit { 28 | Movin.dp("Movin - deinit") 29 | } 30 | 31 | public init(_ duration: TimeInterval, _ timingCurve: UITimingCurveProvider? = nil) { 32 | Movin.dp("Movin - init") 33 | self.duration = duration 34 | self.timingParameters = timingCurve ?? UICubicTimingParameters(animationCurve: .easeInOut) 35 | self.animator = UIViewPropertyAnimator(duration: duration, timingParameters: self.timingParameters) 36 | } 37 | 38 | @discardableResult public func addAnimation(_ a: AnimationCompatible) -> Movin { 39 | self.animations.append(a) 40 | return self 41 | } 42 | 43 | @discardableResult public func addAnimations(_ a: [AnimationCompatible]) -> Movin { 44 | self.animations += a 45 | return self 46 | } 47 | 48 | @discardableResult public func addCompletion(_ c: @escaping (UIViewAnimatingPosition) -> Swift.Void) -> Movin { 49 | self.animator.addCompletion(c) 50 | return self 51 | } 52 | 53 | public func startAnimation(_ mode: MovinMode = .auto) { 54 | Movin.dp("Movin - startAnimation") 55 | if self.animator.state != .inactive { 56 | self.animator.stopAnimation(true) 57 | self.animator.fractionComplete = 0 58 | self.animator.finishAnimation(at: .start) 59 | } 60 | 61 | self.beforeAnimation() 62 | self.configureAnimations(AnimationDirection(self.duration, !self.animator.isReversed)) 63 | 64 | switch mode { 65 | case .auto: 66 | self.animator.startAnimation() 67 | case .interactive(let g): 68 | let canAutoStartAnimation = g.direction.canAutoStartAnimation 69 | g.updateGestureHandler = { [weak self] completed in 70 | if canAutoStartAnimation { 71 | self?.animator.fractionComplete = completed 72 | } 73 | } 74 | g.updateGestureStateHandler = { [weak self] state in 75 | switch state { 76 | case .ended: 77 | if !canAutoStartAnimation { 78 | self?.animator.startAnimation() 79 | } 80 | 81 | if g.isCompleted { 82 | self?.end(true) 83 | } else { 84 | self?.cancel(true) 85 | } 86 | g.unregisterGesture() 87 | case .cancelled, .failed: 88 | self?.cancel(true) 89 | g.unregisterGesture() 90 | default: 91 | break 92 | } 93 | } 94 | if canAutoStartAnimation { 95 | self.animator.startAnimation() 96 | self.animator.pauseAnimation() 97 | } 98 | } 99 | } 100 | 101 | public func configureTransition(_ from: UIViewController, _ to: UIViewController, _ gesture: GestureTransitioning? = nil) -> Transition { 102 | Movin.dp("Movin - configureTransition") 103 | let t = Transition(self, from, to, gesture) 104 | self.transition = t 105 | 106 | return t 107 | } 108 | 109 | public func configureCustomTransition(_ transition: Transition) -> Transition { 110 | Movin.dp("Movin - configureCustomTransition") 111 | self.transition = transition 112 | 113 | return transition 114 | } 115 | 116 | func end(_ isFoward: Bool) { 117 | Movin.dp("Movin - end") 118 | self.finish(isFoward, true) 119 | } 120 | 121 | func cancel(_ isFoward: Bool) { 122 | Movin.dp("Movin - cancel") 123 | self.animator.isReversed = isFoward 124 | self.finish(isFoward, false) 125 | } 126 | 127 | private func finish(_ isFoward: Bool, _ didComplete: Bool) { 128 | Movin.dp("Movin - finish") 129 | self.animator.addCompletion { [weak self] _ in self?.animations.forEach { $0.finishAnimation(isFoward, didComplete) } } 130 | 131 | if self.animator.state == .active { self.animator.startAnimation() } 132 | } 133 | 134 | func beforeAnimation() { 135 | Movin.dp("Movin - beforeAnimation") 136 | self.animations.forEach { $0.beforeAnimation() } 137 | } 138 | 139 | func configureAnimations(_ animationDirection: AnimationDirection) { 140 | Movin.dp("Movin - configureAnimations") 141 | self.animations.forEach { a in 142 | self.animator.addAnimations({ a.aninmate(animationDirection) }, delayFactor: a.delayFactor) 143 | } 144 | } 145 | 146 | func interactiveAnimate(_ fractionComplete: CGFloat) { 147 | Movin.dp("Movin - interactiveAnimate") 148 | self.animations.forEach { $0.interactiveAnimate(fractionComplete) } 149 | } 150 | 151 | func finishInteractiveAnimation(_ interactiveTransitioning: InteractiveTransitioning) { 152 | Movin.dp("Movin - finishInteractiveAnimation") 153 | self.animations.forEach { $0.finishInteractiveAnimation(interactiveTransitioning) } 154 | } 155 | } 156 | 157 | public extension Movin { 158 | 159 | static var isDebugPrintEnabled: Bool = false 160 | 161 | static func dp(_ value: Any?, key: String? = nil) { 162 | if !self.isDebugPrintEnabled { return } 163 | print("[Movin] \(key ?? "") \(value ?? "nil")") 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Sources/Shorthands.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Shorthands.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol MovinExtensionCompatible { 13 | associatedtype CompatibleType 14 | 15 | var mvn: CompatibleType { get } 16 | } 17 | 18 | public struct MovinExtensionCompatibleWrapped { 19 | public let base: Base 20 | 21 | public init(_ base: Base) { 22 | self.base = base 23 | } 24 | } 25 | 26 | public extension MovinExtensionCompatible { 27 | 28 | var mvn: MovinExtensionCompatibleWrapped { 29 | return MovinExtensionCompatibleWrapped(self) 30 | } 31 | } 32 | 33 | extension UIView: MovinExtensionCompatible {} 34 | 35 | public extension MovinExtensionCompatibleWrapped where Base : UIView { 36 | 37 | var alpha: AlphaAnimation { return AlphaAnimation(self.base) } 38 | 39 | var backgroundColor: BackgroundColorAnimation { return BackgroundColorAnimation(self.base) } 40 | 41 | var frame: FrameAnimation { return FrameAnimation(self.base) } 42 | 43 | var point: PointAnimation { return PointAnimation(self.base) } 44 | 45 | var size: SizeAnimation { return SizeAnimation(self.base) } 46 | 47 | var transform: TransformAnimation { return TransformAnimation(self.base) } 48 | 49 | var cornerRadius: CornerRadiusAnimation { return CornerRadiusAnimation(self.base) } 50 | } 51 | 52 | public extension MovinExtensionCompatibleWrapped where Base : UIView { 53 | 54 | var halfSize: CGSize { return self.base.bounds.size.mvn.halfSize } 55 | } 56 | 57 | extension CGSize: MovinExtensionCompatible {} 58 | 59 | public extension MovinExtensionCompatibleWrapped where Base == CGSize { 60 | 61 | var halfSize: CGSize { return CGSize(width: self.base.width * 0.5, height: self.base.height * 0.5) } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/TimingCurve.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TimingCurve.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | @available(iOS 11.0, *) 13 | public class TimingCurve: NSObject, UITimingCurveProvider { 14 | 15 | public let timingCurveType: UITimingCurveType 16 | 17 | public let cubicTimingParameters: UICubicTimingParameters? 18 | 19 | public let springTimingParameters: UISpringTimingParameters? 20 | 21 | public override init() { 22 | self.timingCurveType = .cubic 23 | self.cubicTimingParameters = UICubicTimingParameters(animationCurve: .easeInOut) 24 | self.springTimingParameters = nil 25 | 26 | super.init() 27 | } 28 | 29 | public init(cubic: UICubicTimingParameters, spring: UISpringTimingParameters? = nil) { 30 | if spring != nil { 31 | self.timingCurveType = .composed 32 | } else { 33 | self.timingCurveType = .cubic 34 | } 35 | self.cubicTimingParameters = cubic 36 | self.springTimingParameters = spring 37 | 38 | super.init() 39 | } 40 | 41 | public init(curve: UIView.AnimationCurve, dampingRatio: CGFloat, initialVelocity: CGVector? = nil) { 42 | self.timingCurveType = .composed 43 | self.cubicTimingParameters = UICubicTimingParameters(animationCurve: curve) 44 | 45 | if let v = initialVelocity { 46 | self.springTimingParameters = UISpringTimingParameters(dampingRatio: dampingRatio, initialVelocity: v) 47 | } else { 48 | self.springTimingParameters = UISpringTimingParameters(dampingRatio: dampingRatio) 49 | } 50 | 51 | super.init() 52 | } 53 | 54 | public init(curve: UIView.AnimationCurve, damping: CGFloat, initialVelocity: CGVector, mass: CGFloat, stiffness: CGFloat) { 55 | self.timingCurveType = .composed 56 | self.cubicTimingParameters = UICubicTimingParameters(animationCurve: curve) 57 | self.springTimingParameters = UISpringTimingParameters(mass: mass, stiffness: stiffness, damping: damping, initialVelocity: initialVelocity) 58 | 59 | super.init() 60 | } 61 | 62 | public func copy(with zone: NSZone? = nil) -> Any { 63 | return self 64 | } 65 | 66 | public func encode(with aCoder: NSCoder) { 67 | aCoder.encode(self.timingCurveType.rawValue, forKey: "timingCurveType") 68 | } 69 | 70 | public required init?(coder aDecoder: NSCoder) { 71 | self.timingCurveType = UITimingCurveType(rawValue: aDecoder.decodeObject(forKey: "timingCurveType") as? Int ?? 0) ?? .cubic 72 | self.cubicTimingParameters = UICubicTimingParameters(animationCurve: .easeInOut) 73 | self.springTimingParameters = nil 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Sources/Transition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transition.swift 3 | // Movin 4 | // 5 | // Created by xxxAIRINxxx on 2018/08/02. 6 | // Copyright © 2018 xxxAIRINxxx. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public enum TransitionType { 13 | case push 14 | case pop 15 | case present 16 | case dismiss 17 | 18 | public var reversedType: TransitionType { 19 | switch self { 20 | case .push: return .pop 21 | case .pop: return .push 22 | case .present: return .dismiss 23 | case .dismiss: return .present 24 | } 25 | } 26 | 27 | public var isPresenting: Bool { 28 | return self == .push || self == .present 29 | } 30 | 31 | public var isDismissing: Bool { 32 | return self == .pop || self == .dismiss 33 | } 34 | } 35 | 36 | open class Transition: NSObject { 37 | 38 | public fileprivate(set) weak var movin: Movin! 39 | public let fromVC: UIViewController 40 | public let toVC: UIViewController 41 | public let gestureTransitioning: GestureTransitioning? 42 | 43 | public var customContainerViewSetupHandler: ((TransitionType, UIView) -> Void)? 44 | public var customContainerViewCompletionHandler: ((TransitionType, Bool, UIView) -> Void)? 45 | 46 | public fileprivate(set) var isInteractiveTransition: Bool = false 47 | public fileprivate(set) var animatedTransitioning: AnimatedTransitioning? 48 | public fileprivate(set) var interactiveTransitioning: InteractiveTransitioning? 49 | public fileprivate(set) var completion: ((TransitionType, Bool) -> Void)? 50 | 51 | deinit { 52 | Movin.dp("Transition - deinit") 53 | } 54 | 55 | public init(_ movin: Movin, _ fromVC: UIViewController, _ toVC: UIViewController, _ gestureTransitioning: GestureTransitioning?) { 56 | Movin.dp("Transition - init") 57 | self.movin = movin 58 | self.fromVC = fromVC 59 | self.toVC = toVC 60 | self.gestureTransitioning = gestureTransitioning 61 | 62 | super.init() 63 | 64 | self.handleInteractiveGestureIfNeeded() 65 | } 66 | 67 | @discardableResult public func configureCompletion(_ completion: ((TransitionType, Bool) -> Void)?) -> Transition { 68 | Movin.dp("Transition - configureCompletion") 69 | self.completion = completion 70 | return self 71 | } 72 | 73 | open func prepareTransition(_ type: TransitionType, _ transitionContext: UIViewControllerContextTransitioning) { 74 | Movin.dp("Transition - prepareTransition type: \(type)") 75 | let containerView = transitionContext.containerView 76 | 77 | if let handler = self.customContainerViewSetupHandler { 78 | handler(type, containerView) 79 | } else { 80 | if !self.toVC.isOverContext { 81 | containerView.addSubview(self.fromVC.view) 82 | } 83 | containerView.addSubview(self.toVC.view) 84 | } 85 | 86 | self.movin.beforeAnimation() 87 | self.movin.configureAnimations(AnimationDirection(self.movin.duration, type.isPresenting)) 88 | 89 | if type.isDismissing { 90 | self.movin.animator.startAnimation() 91 | self.movin.animator.pauseAnimation() 92 | self.movin.animator.fractionComplete = 1.0 93 | self.movin.animator.isReversed = true 94 | } 95 | } 96 | 97 | open func currentTransitionType() -> TransitionType? { 98 | Movin.dp("Transition - currentTransitionType") 99 | if let type = self.gestureTransitioning?.currentType() { return type } 100 | if let type = self.animatedTransitioning?.type { return type } 101 | return nil 102 | } 103 | 104 | open func configureInteractiveTransitioningIfNeeded() -> InteractiveTransitioning? { 105 | Movin.dp("Transition - configureInteractiveTransitioningIfNeeded") 106 | if !self.isInteractiveTransition { return nil } 107 | self.setInteractiveTransitioningIfNeeded() 108 | self.handleInteractiveGestureIfNeeded() 109 | return self.interactiveTransitioning 110 | } 111 | 112 | open func setInteractiveTransitioningIfNeeded() { 113 | Movin.dp("Transition - setInteractiveTransitioningIfNeeded") 114 | self.interactiveTransitioning = nil 115 | guard let type = self.gestureTransitioning?.currentType(), self.gestureTransitioning?.hasGesture(type) == true else { return } 116 | self.interactiveTransitioning = InteractiveTransitioning(self, type) 117 | } 118 | 119 | open func handleInteractiveGestureIfNeeded() { 120 | Movin.dp("Transition - handleInteractiveGestureIfNeeded") 121 | guard let type = self.currentTransitionType(), let gesture = self.gestureTransitioning?.gesture(type) else { return } 122 | 123 | gesture.updateGestureHandler = { [weak self] completed in 124 | if #available(iOS 11.0, *) { 125 | self?.movin.interactiveAnimate(completed) 126 | self?.interactiveTransitioning?.update(completed) 127 | } else { 128 | if self?.currentTransitionType()?.isPresenting == true { 129 | self?.movin.interactiveAnimate(completed) 130 | self?.interactiveTransitioning?.update(completed) 131 | } else { 132 | let c = 1.0 - completed 133 | self?.movin.interactiveAnimate(c) 134 | self?.interactiveTransitioning?.update(c) 135 | } 136 | } 137 | } 138 | gesture.updateGestureStateHandler = { [weak self] state in 139 | switch state { 140 | case .began: 141 | self?.startInteractiveTransition() 142 | case .changed: 143 | break 144 | case .ended: 145 | if self?.gestureTransitioning?.gesture(type)?.isCompleted == true { 146 | self?.interactiveTransitioning?.finish() 147 | } else { 148 | self?.interactiveTransitioning?.cancel() 149 | } 150 | case .cancelled, .failed: 151 | self?.interactiveTransitioning?.cancel() 152 | default: 153 | break 154 | } 155 | } 156 | } 157 | 158 | open func startInteractiveTransition() { 159 | Movin.dp("Transition - startInteractiveTransition") 160 | guard let type = self.currentTransitionType() else { return } 161 | self.isInteractiveTransition = true 162 | 163 | switch type { 164 | case .push: 165 | self.fromVC.navigationController?.pushViewController(self.toVC, animated: true) 166 | case .present: 167 | self.fromVC.present(self.toVC, animated: true, completion: nil) 168 | case .pop: 169 | _ = self.fromVC.navigationController?.popViewController(animated: true) 170 | case .dismiss: 171 | self.fromVC.dismiss(animated: true, completion: nil) 172 | } 173 | } 174 | 175 | func finishTransition(_ type: TransitionType, _ didComplete: Bool, _ containerView: UIView) { 176 | Movin.dp("Transition - startInteractiveTransition type: \(type)") 177 | self.gestureTransitioning?.finishTransition(type, didComplete) 178 | 179 | self.animatedTransitioning = nil 180 | self.isInteractiveTransition = false 181 | 182 | if let c = self.customContainerViewCompletionHandler { 183 | c(type, didComplete, containerView) 184 | } else { 185 | self.completion?(type, didComplete) 186 | } 187 | 188 | self.handleInteractiveGestureIfNeeded() 189 | } 190 | } 191 | 192 | extension Transition : UIViewControllerTransitioningDelegate { 193 | 194 | public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 195 | Movin.dp("Transition - animationController forPresented") 196 | self.animatedTransitioning = AnimatedTransitioning(self, .present) 197 | return self.animatedTransitioning 198 | } 199 | 200 | public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 201 | Movin.dp("Transition - animationController forDismissed") 202 | self.animatedTransitioning = AnimatedTransitioning(self, .dismiss) 203 | return self.animatedTransitioning 204 | } 205 | 206 | public func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 207 | Movin.dp("Transition - interactionControllerForPresentation") 208 | return self.configureInteractiveTransitioningIfNeeded() 209 | } 210 | 211 | public func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 212 | Movin.dp("Transition - interactionControllerForDismissal") 213 | return self.configureInteractiveTransitioningIfNeeded() 214 | } 215 | } 216 | 217 | extension Transition: UINavigationControllerDelegate { 218 | 219 | public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 220 | Movin.dp("Transition - navigationController animationControllerFor") 221 | switch operation { 222 | case .push: 223 | self.animatedTransitioning = AnimatedTransitioning(self, .push) 224 | case .pop: 225 | self.animatedTransitioning = AnimatedTransitioning(self, .pop) 226 | case .none: 227 | self.animatedTransitioning = nil 228 | default: 229 | self.animatedTransitioning = nil 230 | } 231 | 232 | return self.animatedTransitioning 233 | } 234 | 235 | public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 236 | Movin.dp("Transition - navigationController interactionControllerFor") 237 | return self.configureInteractiveTransitioningIfNeeded() 238 | } 239 | } 240 | --------------------------------------------------------------------------------