├── .gitignore ├── .travis.yml ├── Assets └── KVRootBaseSideMenu-Swift.gif ├── KVRootBaseSideMenu-Swift ├── KVRootBaseSideMenu-Swift.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── KVRootBaseSideMenu-Swift │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── backward_arrow.imageset │ │ ├── Contents.json │ │ ├── backward_arrow.png │ │ └── backward_arrow@2x.png │ ├── forward_arrow.imageset │ │ ├── Contents.json │ │ ├── forward_arrow@.png │ │ └── forward_arrow@2x.png │ └── menu_icon.imageset │ │ ├── Contents.json │ │ ├── menu_icon@.png │ │ └── menu_icon@2x.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── BaseViewController.swift │ ├── Info.plist │ ├── LeftSideViewController.swift │ ├── RightSideViewController.swift │ ├── SideMenuViewController.swift │ └── ViewController.swift ├── KVRootBaseSideMenu.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── KVRootBaseSideMenu.xcscheme ├── KVRootBaseSideMenu ├── KVAnimationExtention.swift ├── KVConstraintsExtensionsMaster.swift ├── KVCustomSegue.swift ├── KVMenuContainerView.swift └── KVRootBaseSideMenuViewController.swift ├── KVRootBaseSideMenuTests ├── Info.plist └── KVRootBaseSideMenuTests.swift ├── LICENSE.md ├── README.md └── Supporting Files ├── Info.plist └── KVRootBaseSideMenu.h /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | *.DS_Store 4 | **/.DS_Store 5 | 6 | # Xcode 7 | # 8 | # build/ 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | xcuserdata 18 | *.xccheckout 19 | *.moved-aside 20 | DerivedData 21 | *.hmap 22 | *.ipa 23 | *.xcuserstate 24 | 25 | # CocoaPods 26 | # 27 | # We recommend against adding the Pods directory to your .gitignore. However 28 | # you should judge for yourself, the pros and cons are mentioned at: 29 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 30 | # 31 | #Pods/ 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode7.2 2 | language: objective-c 3 | xcode_project: KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift.xcodeproj 4 | 5 | # whitelist 6 | branches: 7 | only: 8 | - master -------------------------------------------------------------------------------- /Assets/KVRootBaseSideMenu-Swift.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/Assets/KVRootBaseSideMenu-Swift.gif -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6B183E311DF630FC0032F3CD /* KVAnimationExtention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E2B1DF630FC0032F3CD /* KVAnimationExtention.swift */; }; 11 | 6B183E331DF630FC0032F3CD /* KVConstraintsExtensionsMaster.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E2D1DF630FC0032F3CD /* KVConstraintsExtensionsMaster.swift */; }; 12 | 6B183E341DF630FC0032F3CD /* KVCustomSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E2E1DF630FC0032F3CD /* KVCustomSegue.swift */; }; 13 | 6B183E351DF630FC0032F3CD /* KVMenuContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E2F1DF630FC0032F3CD /* KVMenuContainerView.swift */; }; 14 | 6B183E361DF630FC0032F3CD /* KVRootBaseSideMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E301DF630FC0032F3CD /* KVRootBaseSideMenuViewController.swift */; }; 15 | 6B298B6D1D342E1E00DADBA5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B6C1D342E1E00DADBA5 /* AppDelegate.swift */; }; 16 | 6B298B6F1D342E1E00DADBA5 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B6E1D342E1E00DADBA5 /* ViewController.swift */; }; 17 | 6B298B721D342E1E00DADBA5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6B298B701D342E1E00DADBA5 /* Main.storyboard */; }; 18 | 6B298B741D342E1E00DADBA5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B298B731D342E1E00DADBA5 /* Assets.xcassets */; }; 19 | 6B298B771D342E1F00DADBA5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6B298B751D342E1F00DADBA5 /* LaunchScreen.storyboard */; }; 20 | 6B298B8D1D342ED500DADBA5 /* LeftSideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B8A1D342ED500DADBA5 /* LeftSideViewController.swift */; }; 21 | 6B298B8E1D342ED500DADBA5 /* RightSideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B8B1D342ED500DADBA5 /* RightSideViewController.swift */; }; 22 | 6B298B8F1D342ED500DADBA5 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B8C1D342ED500DADBA5 /* BaseViewController.swift */; }; 23 | 6B298B911D342EE000DADBA5 /* SideMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B298B901D342EE000DADBA5 /* SideMenuViewController.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXCopyFilesBuildPhase section */ 27 | 6B298B881D342E9A00DADBA5 /* Embed Frameworks */ = { 28 | isa = PBXCopyFilesBuildPhase; 29 | buildActionMask = 2147483647; 30 | dstPath = ""; 31 | dstSubfolderSpec = 10; 32 | files = ( 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 6B183E2B1DF630FC0032F3CD /* KVAnimationExtention.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVAnimationExtention.swift; sourceTree = ""; }; 41 | 6B183E2D1DF630FC0032F3CD /* KVConstraintsExtensionsMaster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVConstraintsExtensionsMaster.swift; sourceTree = ""; }; 42 | 6B183E2E1DF630FC0032F3CD /* KVCustomSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVCustomSegue.swift; sourceTree = ""; }; 43 | 6B183E2F1DF630FC0032F3CD /* KVMenuContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVMenuContainerView.swift; sourceTree = ""; }; 44 | 6B183E301DF630FC0032F3CD /* KVRootBaseSideMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVRootBaseSideMenuViewController.swift; sourceTree = ""; }; 45 | 6B298B691D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "KVRootBaseSideMenu-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 6B298B6C1D342E1E00DADBA5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | 6B298B6E1D342E1E00DADBA5 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 48 | 6B298B711D342E1E00DADBA5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | 6B298B731D342E1E00DADBA5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 6B298B761D342E1F00DADBA5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 6B298B781D342E1F00DADBA5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 6B298B8A1D342ED500DADBA5 /* LeftSideViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LeftSideViewController.swift; sourceTree = ""; }; 53 | 6B298B8B1D342ED500DADBA5 /* RightSideViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RightSideViewController.swift; sourceTree = ""; }; 54 | 6B298B8C1D342ED500DADBA5 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 55 | 6B298B901D342EE000DADBA5 /* SideMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideMenuViewController.swift; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 6B298B661D342E1E00DADBA5 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | 6B183E2A1DF630FC0032F3CD /* KVRootBaseSideMenu */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 6B183E301DF630FC0032F3CD /* KVRootBaseSideMenuViewController.swift */, 73 | 6B183E2F1DF630FC0032F3CD /* KVMenuContainerView.swift */, 74 | 6B183E2E1DF630FC0032F3CD /* KVCustomSegue.swift */, 75 | 6B183E2B1DF630FC0032F3CD /* KVAnimationExtention.swift */, 76 | 6B183E2D1DF630FC0032F3CD /* KVConstraintsExtensionsMaster.swift */, 77 | ); 78 | name = KVRootBaseSideMenu; 79 | path = ../../KVRootBaseSideMenu; 80 | sourceTree = ""; 81 | }; 82 | 6B298B601D342E1E00DADBA5 = { 83 | isa = PBXGroup; 84 | children = ( 85 | 6B298B6B1D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift */, 86 | 6B298B6A1D342E1E00DADBA5 /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 6B298B6A1D342E1E00DADBA5 /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 6B298B691D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift.app */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 6B298B6B1D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 6B183E2A1DF630FC0032F3CD /* KVRootBaseSideMenu */, 102 | 6B298B6C1D342E1E00DADBA5 /* AppDelegate.swift */, 103 | 6B298B901D342EE000DADBA5 /* SideMenuViewController.swift */, 104 | 6B298B8A1D342ED500DADBA5 /* LeftSideViewController.swift */, 105 | 6B298B8B1D342ED500DADBA5 /* RightSideViewController.swift */, 106 | 6B298B8C1D342ED500DADBA5 /* BaseViewController.swift */, 107 | 6B298B6E1D342E1E00DADBA5 /* ViewController.swift */, 108 | 6B298B701D342E1E00DADBA5 /* Main.storyboard */, 109 | 6B298B731D342E1E00DADBA5 /* Assets.xcassets */, 110 | 6B298B751D342E1F00DADBA5 /* LaunchScreen.storyboard */, 111 | 6B298B781D342E1F00DADBA5 /* Info.plist */, 112 | ); 113 | path = "KVRootBaseSideMenu-Swift"; 114 | sourceTree = ""; 115 | }; 116 | /* End PBXGroup section */ 117 | 118 | /* Begin PBXNativeTarget section */ 119 | 6B298B681D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift */ = { 120 | isa = PBXNativeTarget; 121 | buildConfigurationList = 6B298B7B1D342E1F00DADBA5 /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenu-Swift" */; 122 | buildPhases = ( 123 | 6B298B651D342E1E00DADBA5 /* Sources */, 124 | 6B298B661D342E1E00DADBA5 /* Frameworks */, 125 | 6B298B671D342E1E00DADBA5 /* Resources */, 126 | 6B298B881D342E9A00DADBA5 /* Embed Frameworks */, 127 | ); 128 | buildRules = ( 129 | ); 130 | dependencies = ( 131 | ); 132 | name = "KVRootBaseSideMenu-Swift"; 133 | productName = "KVRootBaseSideMenu-Swift"; 134 | productReference = 6B298B691D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift.app */; 135 | productType = "com.apple.product-type.application"; 136 | }; 137 | /* End PBXNativeTarget section */ 138 | 139 | /* Begin PBXProject section */ 140 | 6B298B611D342E1E00DADBA5 /* Project object */ = { 141 | isa = PBXProject; 142 | attributes = { 143 | LastSwiftUpdateCheck = 0720; 144 | LastUpgradeCheck = 0720; 145 | ORGANIZATIONNAME = Keshav; 146 | TargetAttributes = { 147 | 6B298B681D342E1E00DADBA5 = { 148 | CreatedOnToolsVersion = 7.2; 149 | LastSwiftMigration = 0900; 150 | }; 151 | }; 152 | }; 153 | buildConfigurationList = 6B298B641D342E1E00DADBA5 /* Build configuration list for PBXProject "KVRootBaseSideMenu-Swift" */; 154 | compatibilityVersion = "Xcode 3.2"; 155 | developmentRegion = English; 156 | hasScannedForEncodings = 0; 157 | knownRegions = ( 158 | en, 159 | Base, 160 | ); 161 | mainGroup = 6B298B601D342E1E00DADBA5; 162 | productRefGroup = 6B298B6A1D342E1E00DADBA5 /* Products */; 163 | projectDirPath = ""; 164 | projectRoot = ""; 165 | targets = ( 166 | 6B298B681D342E1E00DADBA5 /* KVRootBaseSideMenu-Swift */, 167 | ); 168 | }; 169 | /* End PBXProject section */ 170 | 171 | /* Begin PBXResourcesBuildPhase section */ 172 | 6B298B671D342E1E00DADBA5 /* Resources */ = { 173 | isa = PBXResourcesBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 6B298B771D342E1F00DADBA5 /* LaunchScreen.storyboard in Resources */, 177 | 6B298B741D342E1E00DADBA5 /* Assets.xcassets in Resources */, 178 | 6B298B721D342E1E00DADBA5 /* Main.storyboard in Resources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXResourcesBuildPhase section */ 183 | 184 | /* Begin PBXSourcesBuildPhase section */ 185 | 6B298B651D342E1E00DADBA5 /* Sources */ = { 186 | isa = PBXSourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 6B183E351DF630FC0032F3CD /* KVMenuContainerView.swift in Sources */, 190 | 6B298B6F1D342E1E00DADBA5 /* ViewController.swift in Sources */, 191 | 6B298B8D1D342ED500DADBA5 /* LeftSideViewController.swift in Sources */, 192 | 6B183E341DF630FC0032F3CD /* KVCustomSegue.swift in Sources */, 193 | 6B298B8F1D342ED500DADBA5 /* BaseViewController.swift in Sources */, 194 | 6B183E311DF630FC0032F3CD /* KVAnimationExtention.swift in Sources */, 195 | 6B298B6D1D342E1E00DADBA5 /* AppDelegate.swift in Sources */, 196 | 6B298B911D342EE000DADBA5 /* SideMenuViewController.swift in Sources */, 197 | 6B298B8E1D342ED500DADBA5 /* RightSideViewController.swift in Sources */, 198 | 6B183E361DF630FC0032F3CD /* KVRootBaseSideMenuViewController.swift in Sources */, 199 | 6B183E331DF630FC0032F3CD /* KVConstraintsExtensionsMaster.swift in Sources */, 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXSourcesBuildPhase section */ 204 | 205 | /* Begin PBXVariantGroup section */ 206 | 6B298B701D342E1E00DADBA5 /* Main.storyboard */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | 6B298B711D342E1E00DADBA5 /* Base */, 210 | ); 211 | name = Main.storyboard; 212 | sourceTree = ""; 213 | }; 214 | 6B298B751D342E1F00DADBA5 /* LaunchScreen.storyboard */ = { 215 | isa = PBXVariantGroup; 216 | children = ( 217 | 6B298B761D342E1F00DADBA5 /* Base */, 218 | ); 219 | name = LaunchScreen.storyboard; 220 | sourceTree = ""; 221 | }; 222 | /* End PBXVariantGroup section */ 223 | 224 | /* Begin XCBuildConfiguration section */ 225 | 6B298B791D342E1F00DADBA5 /* Debug */ = { 226 | isa = XCBuildConfiguration; 227 | buildSettings = { 228 | ALWAYS_SEARCH_USER_PATHS = NO; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 243 | COPY_PHASE_STRIP = NO; 244 | DEBUG_INFORMATION_FORMAT = dwarf; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | ENABLE_TESTABILITY = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 257 | GCC_WARN_UNDECLARED_SELECTOR = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 259 | GCC_WARN_UNUSED_FUNCTION = YES; 260 | GCC_WARN_UNUSED_VARIABLE = YES; 261 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 262 | MTL_ENABLE_DEBUG_INFO = YES; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = iphoneos; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 266 | }; 267 | name = Debug; 268 | }; 269 | 6B298B7A1D342E1F00DADBA5 /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ALWAYS_SEARCH_USER_PATHS = NO; 273 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 274 | CLANG_CXX_LIBRARY = "libc++"; 275 | CLANG_ENABLE_MODULES = YES; 276 | CLANG_ENABLE_OBJC_ARC = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_CONSTANT_CONVERSION = YES; 279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 280 | CLANG_WARN_EMPTY_BODY = YES; 281 | CLANG_WARN_ENUM_CONVERSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 284 | CLANG_WARN_UNREACHABLE_CODE = YES; 285 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 286 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 287 | COPY_PHASE_STRIP = NO; 288 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 289 | ENABLE_NS_ASSERTIONS = NO; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | GCC_C_LANGUAGE_STANDARD = gnu99; 292 | GCC_NO_COMMON_BLOCKS = YES; 293 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 294 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 295 | GCC_WARN_UNDECLARED_SELECTOR = YES; 296 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 297 | GCC_WARN_UNUSED_FUNCTION = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 300 | MTL_ENABLE_DEBUG_INFO = NO; 301 | SDKROOT = iphoneos; 302 | VALIDATE_PRODUCT = YES; 303 | }; 304 | name = Release; 305 | }; 306 | 6B298B7C1D342E1F00DADBA5 /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 310 | ENABLE_BITCODE = NO; 311 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 312 | INFOPLIST_FILE = "KVRootBaseSideMenu-Swift/Info.plist"; 313 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 314 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 315 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenu-Swift"; 316 | PRODUCT_NAME = "$(TARGET_NAME)"; 317 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 318 | SWIFT_VERSION = 4.0; 319 | TARGETED_DEVICE_FAMILY = "1,2"; 320 | }; 321 | name = Debug; 322 | }; 323 | 6B298B7D1D342E1F00DADBA5 /* Release */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 327 | ENABLE_BITCODE = NO; 328 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 329 | INFOPLIST_FILE = "KVRootBaseSideMenu-Swift/Info.plist"; 330 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 331 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 332 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenu-Swift"; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 335 | SWIFT_VERSION = 4.0; 336 | TARGETED_DEVICE_FAMILY = "1,2"; 337 | }; 338 | name = Release; 339 | }; 340 | /* End XCBuildConfiguration section */ 341 | 342 | /* Begin XCConfigurationList section */ 343 | 6B298B641D342E1E00DADBA5 /* Build configuration list for PBXProject "KVRootBaseSideMenu-Swift" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | 6B298B791D342E1F00DADBA5 /* Debug */, 347 | 6B298B7A1D342E1F00DADBA5 /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | 6B298B7B1D342E1F00DADBA5 /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenu-Swift" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 6B298B7C1D342E1F00DADBA5 /* Debug */, 356 | 6B298B7D1D342E1F00DADBA5 /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | /* End XCConfigurationList section */ 362 | }; 363 | rootObject = 6B298B611D342E1E00DADBA5 /* Project object */; 364 | } 365 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // KVRootBaseSideMenu-Swift 4 | // 5 | // Created by Keshav on 7/3/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/backward_arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "backward_arrow.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "backward_arrow@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/backward_arrow.imageset/backward_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/backward_arrow.imageset/backward_arrow.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/backward_arrow.imageset/backward_arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/backward_arrow.imageset/backward_arrow@2x.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/forward_arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "forward_arrow@.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "forward_arrow@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/forward_arrow.imageset/forward_arrow@.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/forward_arrow.imageset/forward_arrow@.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/forward_arrow.imageset/forward_arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/forward_arrow.imageset/forward_arrow@2x.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/menu_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "menu_icon@.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "menu_icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/menu_icon.imageset/menu_icon@.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/menu_icon.imageset/menu_icon@.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/menu_icon.imageset/menu_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keshavvishwkarma/KVRootBaseSideMenu-Swift/e41d85f781220efcc35e9d803329ddd9e18b7c33/KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Assets.xcassets/menu_icon.imageset/menu_icon@2x.png -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/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 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/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 | 54 | 63 | 72 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 125 | 134 | 143 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 194 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 235 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 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 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.swift 3 | // DemoApp 4 | // 5 | // Created by Keshav on 7/3/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | 17 | self.title = self.classForCoder.description().components(separatedBy: ".").last! 18 | 19 | let barItemFram = CGRect(x: 0, y: 0, width: 44, height: 44); 20 | 21 | // Customize the UIBarButtonItem 22 | let leftItemCustomeView = UIButton(type: UIButtonType.custom); 23 | leftItemCustomeView.frame = barItemFram; 24 | leftItemCustomeView.setImage(UIImage(named:"backward_arrow"), for: UIControlState()) 25 | 26 | let rightItemCustomeView = UIButton(type: UIButtonType.custom); 27 | rightItemCustomeView.frame = barItemFram; 28 | rightItemCustomeView.setImage(UIImage(named:"forward_arrow"), for: UIControlState()) 29 | 30 | leftItemCustomeView.addTarget(self, action: #selector(BaseViewController.leftButtonAction(_:)), for: UIControlEvents.touchUpInside) 31 | rightItemCustomeView.addTarget(self, action: #selector(BaseViewController.rightButtonAction(_:)), for: UIControlEvents.touchUpInside) 32 | 33 | self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftItemCustomeView); 34 | self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightItemCustomeView); 35 | 36 | } 37 | 38 | // MARK: - IBAction Methods 39 | 40 | @objc func leftButtonAction(_ sender: UIButton) 41 | { 42 | // with orange color 43 | sender.layer.startAnimation(tintColor :UIColor.orange) 44 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleLeft, object: self) 45 | } 46 | 47 | @objc func rightButtonAction(_ sender: UIButton) 48 | { 49 | // with defaultt color 50 | sender.layer.startAnimation() 51 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleRight, object: self) 52 | // OR 53 | // self.sideMenuViewController()?.menuContainerView?.toggleRightSideMenu(); 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/LeftSideViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LeftSideViewController.swift 3 | // KVRootBaseSideMenu-Swift 4 | // 5 | // Created by Keshav on 7/3/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class LeftSideViewController: UIViewController { 12 | 13 | @IBAction func moveToFirstViewControllerButton(_ sender: AnyObject) { 14 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.firstViewController) 15 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleLeft, object: self) 16 | } 17 | 18 | @IBAction func moveToSecondViewControllerButton(_ sender: AnyObject) { 19 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.secondViewController) 20 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleLeft, object: self) 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/RightSideViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RightSideViewController.swift 3 | // SideMenuDemo1 4 | // 5 | // Created by Keshav on 7/3/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class RightSideViewController: UIViewController { 12 | 13 | @IBAction func moveToFirstViewControllerButton(_ sender: AnyObject) { 14 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.firstViewController) 15 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleRight, object: self) 16 | } 17 | 18 | @IBAction func moveToSecondViewControllerButton(_ sender: AnyObject) { 19 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.secondViewController) 20 | NotificationCenter.default.post(name: KVSideMenu.Notifications.toggleRight, object: self) 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/SideMenuViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SideMenuViwController.swift 3 | // KVRootBaseSideMenu-Swift 4 | // 5 | // Created by Keshav on 7/3/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | public extension KVSideMenu 10 | { 11 | // Here define the roots identifier of side menus that must be connected from KVRootBaseSideMenuViewController 12 | // In Storyboard using KVCustomSegue 13 | 14 | static public let leftSideViewController = "LeftSideViewController" 15 | static public let rightSideViewController = "RightSideViewController" 16 | 17 | struct RootsIdentifiers 18 | { 19 | static public let initialViewController = "SecondViewController" 20 | 21 | // All roots viewcontrollers 22 | static public let firstViewController = "FirstViewController" 23 | static public let secondViewController = "SecondViewController" 24 | } 25 | 26 | } 27 | 28 | class SideMenuViewController: KVRootBaseSideMenuViewController 29 | { 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | 33 | // Configure The SideMenu 34 | 35 | leftSideMenuViewController = self.storyboard?.instantiateViewController(withIdentifier: KVSideMenu.leftSideViewController) 36 | rightSideMenuViewController = self.storyboard?.instantiateViewController(withIdentifier: KVSideMenu.rightSideViewController) 37 | 38 | // Set default root 39 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.initialViewController) 40 | 41 | // Set freshRoot value to true/false according to your roots managment polity. By Default value is false. 42 | // If freshRoot value is ture then we will always create a new instance of every root viewcontroller. 43 | // If freshRoot value is ture then we will reuse already created root viewcontroller if exist otherwise create it. 44 | 45 | // self.freshRoot = true 46 | 47 | self.menuContainerView?.delegate = self 48 | 49 | } 50 | } 51 | 52 | extension SideMenuViewController: KVRootBaseSideMenuDelegate 53 | { 54 | func willOpenSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState) { 55 | print(#function) 56 | } 57 | 58 | func didOpenSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState){ 59 | print(#function) 60 | } 61 | 62 | func willCloseSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState){ 63 | print(#function) 64 | } 65 | 66 | func didCloseSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState){ 67 | print(#function) 68 | } 69 | } 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu-Swift/KVRootBaseSideMenu-Swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // KVRootBaseSideMenu-Swift 4 | // 5 | // Created by Keshav on 7/12/16. 6 | // Copyright © 2016 Keshav. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: BaseViewController { 12 | 13 | @IBOutlet weak var disableMenuButton: UIButton! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view, typically from a nib. 18 | } 19 | 20 | override func viewDidAppear(_ animated: Bool) { 21 | super.viewDidAppear(animated) 22 | 23 | disableMenuButton.isSelected = !(sideMenuViewController()?.menuContainerView?.allowPanGesture ?? false) 24 | } 25 | 26 | @IBAction func defaultButtonPressed(_ sender: AnyObject) 27 | { 28 | sideMenuViewController()?.menuContainerView?.animationType = KVSideMenu.AnimationType.default 29 | } 30 | 31 | @IBAction func foldingButtonPressed(_ sender: AnyObject) 32 | { 33 | sideMenuViewController()?.menuContainerView?.animationType = KVSideMenu.AnimationType.folding 34 | } 35 | 36 | @IBAction func windowButtonPressed(_ sender: AnyObject) 37 | { 38 | sideMenuViewController()?.menuContainerView?.animationType = KVSideMenu.AnimationType.window 39 | } 40 | 41 | @IBAction func disablePanGustureButtonPressed(_ sender: UIButton) 42 | { 43 | sender.isSelected = !sender.isSelected 44 | sideMenuViewController()?.menuContainerView?.allowPanGesture = !sender.isSelected 45 | // sideMenuViewController()?.menuContainerView?.allowPanGesture = false 46 | 47 | } 48 | 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6B183DFB1DF62A1F0032F3CD /* KVRootBaseSideMenu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B183DF01DF62A1E0032F3CD /* KVRootBaseSideMenu.framework */; }; 11 | 6B183E001DF62A1F0032F3CD /* KVRootBaseSideMenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183DFF1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.swift */; }; 12 | 6B183E121DF62AF10032F3CD /* KVAnimationExtention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E0C1DF62AF10032F3CD /* KVAnimationExtention.swift */; }; 13 | 6B183E141DF62AF10032F3CD /* KVConstraintsExtensionsMaster.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E0E1DF62AF10032F3CD /* KVConstraintsExtensionsMaster.swift */; }; 14 | 6B183E151DF62AF10032F3CD /* KVCustomSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E0F1DF62AF10032F3CD /* KVCustomSegue.swift */; }; 15 | 6B183E161DF62AF10032F3CD /* KVMenuContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E101DF62AF10032F3CD /* KVMenuContainerView.swift */; }; 16 | 6B183E171DF62AF10032F3CD /* KVRootBaseSideMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B183E111DF62AF10032F3CD /* KVRootBaseSideMenuViewController.swift */; }; 17 | 6B183E281DF630570032F3CD /* KVRootBaseSideMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B183E271DF630570032F3CD /* KVRootBaseSideMenu.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 6B183DFC1DF62A1F0032F3CD /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 6B183DE71DF62A1E0032F3CD /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 6B183DEF1DF62A1E0032F3CD; 26 | remoteInfo = KVRootBaseSideMenu; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 6B183DF01DF62A1E0032F3CD /* KVRootBaseSideMenu.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = KVRootBaseSideMenu.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 6B183DFA1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KVRootBaseSideMenuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 6B183DFF1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KVRootBaseSideMenuTests.swift; sourceTree = ""; }; 34 | 6B183E011DF62A1F0032F3CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 6B183E0C1DF62AF10032F3CD /* KVAnimationExtention.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVAnimationExtention.swift; sourceTree = ""; }; 36 | 6B183E0E1DF62AF10032F3CD /* KVConstraintsExtensionsMaster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVConstraintsExtensionsMaster.swift; sourceTree = ""; }; 37 | 6B183E0F1DF62AF10032F3CD /* KVCustomSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVCustomSegue.swift; sourceTree = ""; }; 38 | 6B183E101DF62AF10032F3CD /* KVMenuContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVMenuContainerView.swift; sourceTree = ""; }; 39 | 6B183E111DF62AF10032F3CD /* KVRootBaseSideMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVRootBaseSideMenuViewController.swift; sourceTree = ""; }; 40 | 6B183E251DF630450032F3CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | 6B183E271DF630570032F3CD /* KVRootBaseSideMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KVRootBaseSideMenu.h; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 6B183DEC1DF62A1E0032F3CD /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | 6B183DF71DF62A1F0032F3CD /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 6B183DFB1DF62A1F0032F3CD /* KVRootBaseSideMenu.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | 6B183DE61DF62A1E0032F3CD = { 64 | isa = PBXGroup; 65 | children = ( 66 | 6B183DF21DF62A1E0032F3CD /* KVRootBaseSideMenu */, 67 | 6B183DFE1DF62A1F0032F3CD /* KVRootBaseSideMenuTests */, 68 | 6B183DF11DF62A1E0032F3CD /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 6B183DF11DF62A1E0032F3CD /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 6B183DF01DF62A1E0032F3CD /* KVRootBaseSideMenu.framework */, 76 | 6B183DFA1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.xctest */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | 6B183DF21DF62A1E0032F3CD /* KVRootBaseSideMenu */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 6B183E111DF62AF10032F3CD /* KVRootBaseSideMenuViewController.swift */, 85 | 6B183E101DF62AF10032F3CD /* KVMenuContainerView.swift */, 86 | 6B183E0F1DF62AF10032F3CD /* KVCustomSegue.swift */, 87 | 6B183E0C1DF62AF10032F3CD /* KVAnimationExtention.swift */, 88 | 6B183E0E1DF62AF10032F3CD /* KVConstraintsExtensionsMaster.swift */, 89 | 6B183E0B1DF62A520032F3CD /* Supporting Files */, 90 | ); 91 | path = KVRootBaseSideMenu; 92 | sourceTree = ""; 93 | }; 94 | 6B183DFE1DF62A1F0032F3CD /* KVRootBaseSideMenuTests */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 6B183DFF1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.swift */, 98 | 6B183E011DF62A1F0032F3CD /* Info.plist */, 99 | ); 100 | path = KVRootBaseSideMenuTests; 101 | sourceTree = ""; 102 | }; 103 | 6B183E0B1DF62A520032F3CD /* Supporting Files */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 6B183E271DF630570032F3CD /* KVRootBaseSideMenu.h */, 107 | 6B183E251DF630450032F3CD /* Info.plist */, 108 | ); 109 | name = "Supporting Files"; 110 | path = "../Supporting Files"; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXHeadersBuildPhase section */ 116 | 6B183DED1DF62A1E0032F3CD /* Headers */ = { 117 | isa = PBXHeadersBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | 6B183E281DF630570032F3CD /* KVRootBaseSideMenu.h in Headers */, 121 | ); 122 | runOnlyForDeploymentPostprocessing = 0; 123 | }; 124 | /* End PBXHeadersBuildPhase section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | 6B183DEF1DF62A1E0032F3CD /* KVRootBaseSideMenu */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = 6B183E041DF62A1F0032F3CD /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenu" */; 130 | buildPhases = ( 131 | 6B183DEB1DF62A1E0032F3CD /* Sources */, 132 | 6B183DEC1DF62A1E0032F3CD /* Frameworks */, 133 | 6B183DED1DF62A1E0032F3CD /* Headers */, 134 | 6B183DEE1DF62A1E0032F3CD /* Resources */, 135 | ); 136 | buildRules = ( 137 | ); 138 | dependencies = ( 139 | ); 140 | name = KVRootBaseSideMenu; 141 | productName = KVRootBaseSideMenu; 142 | productReference = 6B183DF01DF62A1E0032F3CD /* KVRootBaseSideMenu.framework */; 143 | productType = "com.apple.product-type.framework"; 144 | }; 145 | 6B183DF91DF62A1F0032F3CD /* KVRootBaseSideMenuTests */ = { 146 | isa = PBXNativeTarget; 147 | buildConfigurationList = 6B183E071DF62A1F0032F3CD /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenuTests" */; 148 | buildPhases = ( 149 | 6B183DF61DF62A1F0032F3CD /* Sources */, 150 | 6B183DF71DF62A1F0032F3CD /* Frameworks */, 151 | 6B183DF81DF62A1F0032F3CD /* Resources */, 152 | ); 153 | buildRules = ( 154 | ); 155 | dependencies = ( 156 | 6B183DFD1DF62A1F0032F3CD /* PBXTargetDependency */, 157 | ); 158 | name = KVRootBaseSideMenuTests; 159 | productName = KVRootBaseSideMenuTests; 160 | productReference = 6B183DFA1DF62A1F0032F3CD /* KVRootBaseSideMenuTests.xctest */; 161 | productType = "com.apple.product-type.bundle.unit-test"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | 6B183DE71DF62A1E0032F3CD /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | LastSwiftUpdateCheck = 0720; 170 | LastUpgradeCheck = 0830; 171 | ORGANIZATIONNAME = "com.keshav. KVRootBaseSideMenu"; 172 | TargetAttributes = { 173 | 6B183DEF1DF62A1E0032F3CD = { 174 | CreatedOnToolsVersion = 7.2; 175 | LastSwiftMigration = 0830; 176 | }; 177 | 6B183DF91DF62A1F0032F3CD = { 178 | CreatedOnToolsVersion = 7.2; 179 | LastSwiftMigration = 0830; 180 | }; 181 | }; 182 | }; 183 | buildConfigurationList = 6B183DEA1DF62A1E0032F3CD /* Build configuration list for PBXProject "KVRootBaseSideMenu" */; 184 | compatibilityVersion = "Xcode 3.2"; 185 | developmentRegion = English; 186 | hasScannedForEncodings = 0; 187 | knownRegions = ( 188 | en, 189 | ); 190 | mainGroup = 6B183DE61DF62A1E0032F3CD; 191 | productRefGroup = 6B183DF11DF62A1E0032F3CD /* Products */; 192 | projectDirPath = ""; 193 | projectRoot = ""; 194 | targets = ( 195 | 6B183DEF1DF62A1E0032F3CD /* KVRootBaseSideMenu */, 196 | 6B183DF91DF62A1F0032F3CD /* KVRootBaseSideMenuTests */, 197 | ); 198 | }; 199 | /* End PBXProject section */ 200 | 201 | /* Begin PBXResourcesBuildPhase section */ 202 | 6B183DEE1DF62A1E0032F3CD /* Resources */ = { 203 | isa = PBXResourcesBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | }; 209 | 6B183DF81DF62A1F0032F3CD /* Resources */ = { 210 | isa = PBXResourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXResourcesBuildPhase section */ 217 | 218 | /* Begin PBXSourcesBuildPhase section */ 219 | 6B183DEB1DF62A1E0032F3CD /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | 6B183E121DF62AF10032F3CD /* KVAnimationExtention.swift in Sources */, 224 | 6B183E161DF62AF10032F3CD /* KVMenuContainerView.swift in Sources */, 225 | 6B183E141DF62AF10032F3CD /* KVConstraintsExtensionsMaster.swift in Sources */, 226 | 6B183E171DF62AF10032F3CD /* KVRootBaseSideMenuViewController.swift in Sources */, 227 | 6B183E151DF62AF10032F3CD /* KVCustomSegue.swift in Sources */, 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | }; 231 | 6B183DF61DF62A1F0032F3CD /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 6B183E001DF62A1F0032F3CD /* KVRootBaseSideMenuTests.swift in Sources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXSourcesBuildPhase section */ 240 | 241 | /* Begin PBXTargetDependency section */ 242 | 6B183DFD1DF62A1F0032F3CD /* PBXTargetDependency */ = { 243 | isa = PBXTargetDependency; 244 | target = 6B183DEF1DF62A1E0032F3CD /* KVRootBaseSideMenu */; 245 | targetProxy = 6B183DFC1DF62A1F0032F3CD /* PBXContainerItemProxy */; 246 | }; 247 | /* End PBXTargetDependency section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | 6B183E021DF62A1F0032F3CD /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 255 | CLANG_CXX_LIBRARY = "libc++"; 256 | CLANG_ENABLE_MODULES = YES; 257 | CLANG_ENABLE_OBJC_ARC = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_CONSTANT_CONVERSION = YES; 260 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 261 | CLANG_WARN_EMPTY_BODY = YES; 262 | CLANG_WARN_ENUM_CONVERSION = YES; 263 | CLANG_WARN_INFINITE_RECURSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 266 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 267 | CLANG_WARN_UNREACHABLE_CODE = YES; 268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 269 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 270 | COPY_PHASE_STRIP = NO; 271 | CURRENT_PROJECT_VERSION = 1; 272 | DEBUG_INFORMATION_FORMAT = dwarf; 273 | ENABLE_STRICT_OBJC_MSGSEND = YES; 274 | ENABLE_TESTABILITY = YES; 275 | GCC_C_LANGUAGE_STANDARD = gnu99; 276 | GCC_DYNAMIC_NO_PIC = NO; 277 | GCC_NO_COMMON_BLOCKS = YES; 278 | GCC_OPTIMIZATION_LEVEL = 0; 279 | GCC_PREPROCESSOR_DEFINITIONS = ( 280 | "DEBUG=1", 281 | "$(inherited)", 282 | ); 283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 285 | GCC_WARN_UNDECLARED_SELECTOR = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 287 | GCC_WARN_UNUSED_FUNCTION = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 290 | MTL_ENABLE_DEBUG_INFO = YES; 291 | ONLY_ACTIVE_ARCH = YES; 292 | SDKROOT = iphoneos; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 294 | TARGETED_DEVICE_FAMILY = "1,2"; 295 | VERSIONING_SYSTEM = "apple-generic"; 296 | VERSION_INFO_PREFIX = ""; 297 | }; 298 | name = Debug; 299 | }; 300 | 6B183E031DF62A1F0032F3CD /* Release */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | ALWAYS_SEARCH_USER_PATHS = NO; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 305 | CLANG_CXX_LIBRARY = "libc++"; 306 | CLANG_ENABLE_MODULES = YES; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_WARN_BOOL_CONVERSION = YES; 309 | CLANG_WARN_CONSTANT_CONVERSION = YES; 310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 311 | CLANG_WARN_EMPTY_BODY = YES; 312 | CLANG_WARN_ENUM_CONVERSION = YES; 313 | CLANG_WARN_INFINITE_RECURSION = YES; 314 | CLANG_WARN_INT_CONVERSION = YES; 315 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | CURRENT_PROJECT_VERSION = 1; 322 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 323 | ENABLE_NS_ASSERTIONS = NO; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu99; 326 | GCC_NO_COMMON_BLOCKS = YES; 327 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 328 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 329 | GCC_WARN_UNDECLARED_SELECTOR = YES; 330 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 331 | GCC_WARN_UNUSED_FUNCTION = YES; 332 | GCC_WARN_UNUSED_VARIABLE = YES; 333 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 334 | MTL_ENABLE_DEBUG_INFO = NO; 335 | SDKROOT = iphoneos; 336 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 337 | TARGETED_DEVICE_FAMILY = "1,2"; 338 | VALIDATE_PRODUCT = YES; 339 | VERSIONING_SYSTEM = "apple-generic"; 340 | VERSION_INFO_PREFIX = ""; 341 | }; 342 | name = Release; 343 | }; 344 | 6B183E051DF62A1F0032F3CD /* Debug */ = { 345 | isa = XCBuildConfiguration; 346 | buildSettings = { 347 | CLANG_ENABLE_MODULES = YES; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 349 | DEFINES_MODULE = YES; 350 | DYLIB_COMPATIBILITY_VERSION = 1; 351 | DYLIB_CURRENT_VERSION = 1; 352 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 353 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 354 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 355 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 356 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 357 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenu"; 358 | PRODUCT_NAME = "$(TARGET_NAME)"; 359 | SKIP_INSTALL = YES; 360 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 361 | SWIFT_VERSION = 3.0; 362 | }; 363 | name = Debug; 364 | }; 365 | 6B183E061DF62A1F0032F3CD /* Release */ = { 366 | isa = XCBuildConfiguration; 367 | buildSettings = { 368 | CLANG_ENABLE_MODULES = YES; 369 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 370 | DEFINES_MODULE = YES; 371 | DYLIB_COMPATIBILITY_VERSION = 1; 372 | DYLIB_CURRENT_VERSION = 1; 373 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 374 | INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; 375 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 376 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 377 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 378 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenu"; 379 | PRODUCT_NAME = "$(TARGET_NAME)"; 380 | SKIP_INSTALL = YES; 381 | SWIFT_VERSION = 3.0; 382 | }; 383 | name = Release; 384 | }; 385 | 6B183E081DF62A1F0032F3CD /* Debug */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | INFOPLIST_FILE = KVRootBaseSideMenuTests/Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 390 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenuTests"; 391 | PRODUCT_NAME = "$(TARGET_NAME)"; 392 | SWIFT_VERSION = 3.0; 393 | }; 394 | name = Debug; 395 | }; 396 | 6B183E091DF62A1F0032F3CD /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | INFOPLIST_FILE = KVRootBaseSideMenuTests/Info.plist; 400 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 401 | PRODUCT_BUNDLE_IDENTIFIER = "Keshav-Vishwkarma.KVRootBaseSideMenuTests"; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | SWIFT_VERSION = 3.0; 404 | }; 405 | name = Release; 406 | }; 407 | /* End XCBuildConfiguration section */ 408 | 409 | /* Begin XCConfigurationList section */ 410 | 6B183DEA1DF62A1E0032F3CD /* Build configuration list for PBXProject "KVRootBaseSideMenu" */ = { 411 | isa = XCConfigurationList; 412 | buildConfigurations = ( 413 | 6B183E021DF62A1F0032F3CD /* Debug */, 414 | 6B183E031DF62A1F0032F3CD /* Release */, 415 | ); 416 | defaultConfigurationIsVisible = 0; 417 | defaultConfigurationName = Release; 418 | }; 419 | 6B183E041DF62A1F0032F3CD /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenu" */ = { 420 | isa = XCConfigurationList; 421 | buildConfigurations = ( 422 | 6B183E051DF62A1F0032F3CD /* Debug */, 423 | 6B183E061DF62A1F0032F3CD /* Release */, 424 | ); 425 | defaultConfigurationIsVisible = 0; 426 | defaultConfigurationName = Release; 427 | }; 428 | 6B183E071DF62A1F0032F3CD /* Build configuration list for PBXNativeTarget "KVRootBaseSideMenuTests" */ = { 429 | isa = XCConfigurationList; 430 | buildConfigurations = ( 431 | 6B183E081DF62A1F0032F3CD /* Debug */, 432 | 6B183E091DF62A1F0032F3CD /* Release */, 433 | ); 434 | defaultConfigurationIsVisible = 0; 435 | defaultConfigurationName = Release; 436 | }; 437 | /* End XCConfigurationList section */ 438 | }; 439 | rootObject = 6B183DE71DF62A1E0032F3CD /* Project object */; 440 | } 441 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu.xcodeproj/xcshareddata/xcschemes/KVRootBaseSideMenu.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu/KVAnimationExtention.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVAnimationExtention.swift 3 | // https://github.com/keshavvishwkarma/KVRootBaseSideMenu-Swift.git 4 | // 5 | // Distributed under the MIT License. 6 | // 7 | // Created by Keshav on 7/26/16. 8 | // Copyright © 2016 Keshav. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | // this software and associated documentation files (the "Software"), to deal in 12 | // the Software without restriction, including without limitation the rights to 13 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | // of the Software, and to permit persons to whom the Software is furnished to do 15 | // so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | import UIKit 30 | 31 | private var xoAssociationKey: UInt8 = 0 32 | 33 | extension CALayer 34 | { 35 | var associatedObject: CALayer? { 36 | get { 37 | return objc_getAssociatedObject(self, &xoAssociationKey) as? CALayer 38 | } 39 | set(newValue) { 40 | objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 41 | } 42 | } 43 | } 44 | 45 | extension CALayer { 46 | 47 | public func startAnimation(tintColor: UIColor? = UIColor.orange) 48 | { 49 | if (associatedObject == nil) 50 | { 51 | let _circleLayer: CALayer = CALayer() 52 | associatedObject = _circleLayer 53 | addSublayer(_circleLayer) 54 | _circleLayer.name = "KVAnimationExtention" 55 | 56 | let size : CGFloat = max(self.bounds.height, self.bounds.width); 57 | let dx : CGFloat = (self.bounds.size.width - size) / 2.0 58 | let dy : CGFloat = (self.bounds.size.height - size) / 2.0 59 | 60 | _circleLayer.opacity = 0.0 61 | 62 | CATransaction.begin() 63 | CATransaction.setDisableActions(true) 64 | CATransaction.setCompletionBlock { 65 | self.stopAnimation() 66 | } 67 | 68 | _circleLayer.frame = CGRect(x: dx, y: dy, width: size, height: size) 69 | _circleLayer.cornerRadius = size / 2.0 70 | _circleLayer.backgroundColor = tintColor?.cgColor; 71 | 72 | let circleLayerAnimation : CABasicAnimation = CABasicAnimation(keyPath: "transform.scale") 73 | circleLayerAnimation.fromValue = NSNumber(value: 0.2 as Double) 74 | circleLayerAnimation.toValue = NSNumber(value: 1.1 as Double) 75 | circleLayerAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 76 | 77 | let opacityAnimation : CABasicAnimation = CABasicAnimation(keyPath: "opacity") 78 | opacityAnimation.fromValue = NSNumber(value: 0.75 as Double) 79 | opacityAnimation.toValue = NSNumber(value: 0.0 as Double) 80 | opacityAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 81 | 82 | let groupAnim : CAAnimationGroup = CAAnimationGroup() 83 | groupAnim.duration = 0.75 84 | groupAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 85 | groupAnim.isRemovedOnCompletion = true 86 | // groupAnim.fillMode = kCAFillModeForwards 87 | groupAnim.fillMode = kCAFillModeBoth 88 | groupAnim.animations = [circleLayerAnimation, opacityAnimation] 89 | _circleLayer.add(groupAnim, forKey: "animation") 90 | 91 | CATransaction.commit() 92 | } 93 | 94 | } 95 | 96 | fileprivate func stopAnimation() { 97 | associatedObject?.removeFromSuperlayer() 98 | associatedObject = nil 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu/KVConstraintsExtensionsMaster.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVConstraintsExtensionsMaster.swift 3 | // https://github.com/keshavvishwkarma/KVConstraintExtensionsMaster.git 4 | // 5 | // Distributed under the MIT License. 6 | // 7 | // Created by Keshav on 7/28/16. 8 | // Copyright © 2016 Keshav. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | // this software and associated documentation files (the "Software"), to deal in 12 | // the Software without restriction, including without limitation the rights to 13 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | // of the Software, and to permit persons to whom the Software is furnished to do 15 | // so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | // 29 | 30 | import UIKit 31 | 32 | typealias View = UIView 33 | 34 | //********* DEFINE NEW OPERATOR *********// 35 | infix operator <-; infix operator +==; infix operator *==; infix operator |==| 36 | 37 | //********* DEFINE NEW INTERFACE *********// 38 | 39 | protocol Addable:class { 40 | /// TO ADD SINGLE CONSTRAINT 41 | static func +(lhs: Self, rhs: NSLayoutConstraint) -> NSLayoutConstraint 42 | } 43 | 44 | protocol Removable:class { 45 | /// TO REMOVE SINGLE CONSTRAINT 46 | static func -(lhs: Self, rhs: NSLayoutConstraint) -> NSLayoutConstraint 47 | } 48 | 49 | protocol Accessable:class { 50 | /// TO ACCESS CONSTRAINT BASED ON LAYOUT ATTRIBUTE 51 | static func <-(lhs: Self, rhs: NSLayoutAttribute) -> NSLayoutConstraint? 52 | } 53 | 54 | protocol LayoutRelationable:class 55 | { 56 | /// TO ADD SINGLE EQUAL RELATION CONSTRAINT 57 | static func +==(lhs: Self, rhs: NSLayoutAttribute) -> NSLayoutConstraint 58 | 59 | /// TO ADD MULTIPLE EQUAL RELATION CONSTRAINTS 60 | static func +==(lhs: Self, rhs: [NSLayoutAttribute]) -> [NSLayoutConstraint] 61 | 62 | /// TO ADD SINGLE EQUAL RELATION CONSTRAINT WITH MULTIPLEIR 63 | static func *==(lhs: Self, rhs: (NSLayoutAttribute, CGFloat)) -> NSLayoutConstraint 64 | 65 | /// TO ADD SIBLING CONSTRAINT WITH EQUAL RELATION 66 | static func |==|(lhs: Self, rhs: (NSLayoutAttribute, NSLayoutAttribute, Self)) -> NSLayoutConstraint 67 | } 68 | 69 | extension View : Addable, Removable, Accessable, LayoutRelationable {} 70 | 71 | // MARK: Addable 72 | 73 | extension Addable where Self: View 74 | { 75 | /// To add single constraint on the receiver view 76 | @discardableResult static func +(lhs: Self, rhs: NSLayoutConstraint) -> NSLayoutConstraint { 77 | return lhs.applyPreparedConstraintInView(constraint: rhs) 78 | } 79 | } 80 | 81 | // MARK: Removable 82 | extension Removable where Self: View 83 | { 84 | /// To remove single constraint from the receiver view 85 | @discardableResult static func -(lhs: Self, rhs: NSLayoutConstraint) -> NSLayoutConstraint { 86 | lhs.removeConstraint(rhs); return rhs 87 | } 88 | } 89 | 90 | // MARK: Accessable 91 | extension Accessable where Self: View 92 | { 93 | @discardableResult static func <-(lhs: Self, rhs: NSLayoutAttribute) -> NSLayoutConstraint?{ 94 | return lhs.accessAppliedConstraintBy(attribute: rhs) 95 | } 96 | } 97 | 98 | // MARK: LayoutRelationable 99 | 100 | extension LayoutRelationable where Self: View 101 | { 102 | /// (leftContainerView +== .Top).constant = 0 103 | @discardableResult static func +==(lhs: Self, rhs: NSLayoutAttribute) -> NSLayoutConstraint { 104 | return lhs.superview! + lhs.prepareConstraintToSuperview(attribute: rhs) 105 | } 106 | 107 | /// To add multiple constraint with defaultt constant value that is - 0 (Zero). 108 | @discardableResult static func +==(lhs: Self, rhs: [NSLayoutAttribute] ) -> [NSLayoutConstraint] { 109 | return rhs.map { lhs.superview! + lhs.prepareConstraintToSuperview(attribute: $0) } 110 | } 111 | 112 | /// (leftContainerView *== (.Top, multiplier) ).constant = 0 113 | @discardableResult static func *==(lhs: Self, rhs: (NSLayoutAttribute, CGFloat)) -> NSLayoutConstraint { 114 | return lhs.superview! + lhs.prepareConstraintToSuperview(attribute: rhs.0, multiplier: rhs.1) 115 | } 116 | 117 | @discardableResult static func |==|(lhs: Self, rhs: (NSLayoutAttribute, NSLayoutAttribute, Self)) -> NSLayoutConstraint { 118 | return lhs.applyConstraintFromSiblingView(attribute: rhs.0, toAttribute: rhs.1, ofView: rhs.2) 119 | } 120 | } 121 | 122 | /// Types adopting the `AutoLayoutView` protocol can be used to construct Views. 123 | protocol AutoLayoutView {} 124 | extension View : AutoLayoutView {} 125 | 126 | extension AutoLayoutView where Self : View { 127 | 128 | /// This method is used to create new instance of ui elements for autolayout. 129 | static func prepareAutoLayoutView() -> Self { 130 | let preparedView = Self() 131 | preparedView.translatesAutoresizingMaskIntoConstraints = false 132 | return preparedView 133 | } 134 | 135 | /// This method is used to prepare already created instance of ui elements for autolayout. 136 | func prepareAutoLayoutView() { 137 | translatesAutoresizingMaskIntoConstraints = false 138 | } 139 | 140 | } 141 | 142 | private extension View 143 | { 144 | class final func prepareConstraint(_ firstView: View!, attribute attr1: NSLayoutAttribute, secondView: View?=nil, attribute attr2: NSLayoutAttribute = .notAnAttribute, relation: NSLayoutRelation = .equal, multiplier: CGFloat = 1, constant: CGFloat = 0) -> NSLayoutConstraint! 145 | { 146 | assert(!multiplier.isInfinite, "Multiplier/Ratio of view must not be INFINITY.") 147 | assert(!multiplier.isNaN, "Multiplier/Ratio of view must not be NaN.") 148 | 149 | assert(!constant.isInfinite, "constant of view must not be INFINITY.") 150 | assert(!constant.isNaN, "constant of view must not be NaN.") 151 | 152 | return KVConstraintsExtensionsMaster.prepareConstraint(firstView, attribute: attr1, relation: relation, toItem: secondView, attribute: attr2, multiplier: multiplier, constant: constant) 153 | } 154 | } 155 | 156 | //MARK: TO PREPARE CONSTRAINTS 157 | 158 | extension View { 159 | 160 | /// Generalized public constraint methods for views 161 | final func prepareConstraintToSuperview(attribute attr1: NSLayoutAttribute, relation: NSLayoutRelation = .equal, multiplier:CGFloat = 1.0) -> NSLayoutConstraint! { 162 | assert(superview != nil, "You should have addSubView on any other its called's Superview \(self)"); 163 | return View.prepareConstraint(self, attribute: attr1, secondView: superview, attribute:attr1, relation: relation, multiplier:multiplier) 164 | } 165 | 166 | /// Prepare constraint of one sibling view to other sibling view and add it into its superview view. 167 | final func prepareConstraintFromSiblingView(attribute attr1: NSLayoutAttribute, toAttribute attr2:NSLayoutAttribute, ofView otherSiblingView: View, relation:NSLayoutRelation = .equal, multiplier:CGFloat = 1.0) -> NSLayoutConstraint! { 168 | assert(((NSSet(array: [superview!,otherSiblingView.superview!])).count == 1), "All the sibling views must belong to same superview") 169 | 170 | return View.prepareConstraint(self, attribute: attr1, secondView:otherSiblingView, attribute:attr2, relation:relation, multiplier: multiplier) 171 | } 172 | 173 | } 174 | 175 | // MARK: TO ADD CONSTRAINT AND ACCESS APPLIED/ADDED CONSTRAINTS 176 | extension View 177 | { 178 | // MARK: - Add constraints in the non cumulative 179 | 180 | /// This is the common methods to add the constraint in the receiver only once. If constraint already exists then it will only update that constraint and return that constraint. 181 | final func applyPreparedConstraintInView(constraint c: NSLayoutConstraint) -> NSLayoutConstraint 182 | { 183 | // If this constraint is already added then it update the constraint values else added new constraint. 184 | let appliedConstraint = self.constraints.containsApplied(constraint: c) 185 | 186 | if (appliedConstraint != nil) { 187 | appliedConstraint!.constant = c.constant 188 | return appliedConstraint! 189 | } 190 | 191 | addConstraint(c) 192 | return c 193 | 194 | } 195 | 196 | final func applyConstraintFromSiblingView(attribute attr1: NSLayoutAttribute, toAttribute attr2:NSLayoutAttribute, ofView otherSiblingView: View) -> NSLayoutConstraint { 197 | let c = self.prepareConstraintFromSiblingView(attribute: attr1, toAttribute: attr2, ofView: otherSiblingView) 198 | return self.superview! + c! 199 | } 200 | 201 | /// MARK: - Access Applied Constraint By Attributes From a specific View 202 | final func accessAppliedConstraintBy(attribute attr: NSLayoutAttribute, relation: NSLayoutRelation = .equal)->NSLayoutConstraint? { 203 | let c = self.prepareConstraintToSuperview(attribute: attr, relation: relation) 204 | let appliedConstraint = self.superview?.constraints.containsApplied(constraint: c!) 205 | return appliedConstraint 206 | } 207 | 208 | final func accessAppliedConstraintBy(attribute attr: NSLayoutAttribute, relation: NSLayoutRelation = .equal, completionHandler: @escaping ((NSLayoutConstraint?) -> Void)){ 209 | DispatchQueue.main.async { () -> Void in 210 | completionHandler(self.accessAppliedConstraintBy(attribute: attr, relation: relation)) 211 | } 212 | } 213 | 214 | } 215 | 216 | public struct KVConstraintsExtensionsMaster { 217 | /// :name: prepareConstraint 218 | public static func prepareConstraint(_ item: AnyObject, attribute attr1: NSLayoutAttribute, relation: NSLayoutRelation = .equal, toItem: AnyObject?=nil, attribute attr2: NSLayoutAttribute = .notAnAttribute, multiplier: CGFloat = 1.0, constant: CGFloat = 0) -> NSLayoutConstraint! { 219 | return NSLayoutConstraint(item: item, attribute: attr1, relatedBy: relation, toItem: toItem, attribute: attr2, multiplier: multiplier, constant: constant) 220 | } 221 | 222 | } 223 | 224 | private extension NSLayoutConstraint { 225 | final func isEqualTo(constraint c:NSLayoutConstraint)-> Bool { 226 | return firstItem === c.firstItem && firstAttribute == c.firstAttribute && relation == c.relation && secondItem === c.secondItem && secondAttribute == c.secondAttribute && multiplier == c.multiplier 227 | } 228 | 229 | } 230 | 231 | private extension Array where Element: NSLayoutConstraint { 232 | func containsApplied(constraint c: Element) -> Element? { 233 | return reversed().filter { $0.isEqualTo(constraint: c)}.first 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu/KVCustomSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVCustomSegue.swift 3 | // https://github.com/keshavvishwkarma/KVRootBaseSideMenu-Swift.git 4 | // 5 | // Distributed under the MIT License. 6 | // 7 | // Created by Keshav on 7/3/16. 8 | // Copyright © 2016 Keshav. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | // this software and associated documentation files (the "Software"), to deal in 12 | // the Software without restriction, including without limitation the rights to 13 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | // of the Software, and to permit persons to whom the Software is furnished to do 15 | // so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | // 29 | 30 | import UIKit 31 | 32 | open class KVCustomSegue: UIStoryboardSegue { 33 | 34 | override open func perform() 35 | { 36 | // Must Call this method from Source ViewController 37 | if self.source.shouldPerformSegue(withIdentifier: self.identifier!, sender: self) { 38 | 39 | } 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu/KVMenuContainerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVMenuContainerView.swift 3 | // https://github.com/keshavvishwkarma/KVRootBaseSideMenu-Swift.git 4 | // 5 | // Distributed under the MIT License. 6 | // 7 | // Created by Keshav on 7/3/16. 8 | // Copyright © 2016 Keshav. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | // this software and associated documentation files (the "Software"), to deal in 12 | // the Software without restriction, including without limitation the rights to 13 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | // of the Software, and to permit persons to whom the Software is furnished to do 15 | // so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | // 29 | 30 | import UIKit 31 | 32 | public struct KVSideMenu 33 | { 34 | public struct Notifications { 35 | static public let toggleLeft = Notification.Name(rawValue: "ToggleLeftSideMenuNotification") 36 | static public let toggleRight = Notification.Name(rawValue: "ToggleRightSideMenuNotification") 37 | static public let close = Notification.Name(rawValue: "CloseSideMenuNotification") 38 | } 39 | 40 | @objc 41 | public enum SideMenuState: Int { 42 | case none, left, right 43 | init() { 44 | self = .none 45 | } 46 | } 47 | 48 | @objc 49 | public enum AnimationType: Int 50 | { 51 | case `default`, window, folding 52 | public init() { 53 | self = .`default` 54 | } 55 | } 56 | 57 | } 58 | 59 | @objc(KVRootBaseSideMenuDelegate) 60 | public protocol KVRootBaseSideMenuDelegate: class { 61 | /** 62 | An optional delegation method that is fired before the KVMenuContainerView opens. 63 | */ 64 | @objc optional func willOpenSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState) 65 | 66 | /** 67 | An optional delegation method that is fired after the KVMenuContainerView opened. 68 | */ 69 | @objc optional func didOpenSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState) 70 | 71 | /** 72 | An optional delegation method that is fired before the KVMenuContainerView closes. 73 | */ 74 | @objc optional func willCloseSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState) 75 | 76 | /** 77 | An optional delegation method that is fired after the KVMenuContainerView closed. 78 | */ 79 | @objc optional func didCloseSideMenuView(_ sideMenuView: KVMenuContainerView, state: KVSideMenu.SideMenuState) 80 | } 81 | 82 | @objc(KVMenuContainerView) 83 | open class KVMenuContainerView: UIView 84 | { 85 | // MARK: - Properties 86 | 87 | /// A KVRootBaseSideMenuDelegate property used to bind the delegation object. 88 | open weak var delegate: KVRootBaseSideMenuDelegate? 89 | 90 | open var animationType: KVSideMenu.AnimationType = KVSideMenu.AnimationType() 91 | open var allowTapGesture : Bool = true 92 | open var allowPanGesture : Bool = true 93 | 94 | /// A Boolean property that indicates either left swipe is enables or disables . 95 | open var allowLeftPaning: Bool = false { 96 | didSet{ 97 | rightContainerView.subviews.first?.removeFromSuperview() 98 | } 99 | } 100 | 101 | /// A Boolean property that indicates either right swipe is enables or disables . 102 | open var allowRightPaning : Bool = false { 103 | didSet{ 104 | leftContainerView.subviews.first?.removeFromSuperview() 105 | } 106 | } 107 | 108 | /** 109 | A CGFloat property that accesses the leftContainerView and 110 | rightContainerView threshold of the KVMenuContainerView. 111 | 112 | When the panning gesture has ended, if the position is 113 | beyond the threshold, either left or right side menu 114 | is opened, if it is below the threshold, the side menu is closed. 115 | */ 116 | fileprivate let thresholdFactor: CGFloat = 0.25 117 | 118 | open var KVSideMenuOffsetValueInRatio: CGFloat = 0.75 119 | open var KVSideMenuHideShowDuration : CGFloat = 0.4 120 | 121 | fileprivate let transformScale = CGAffineTransform(scaleX: 1.0, y: 0.8) 122 | 123 | open fileprivate(set) var leftContainerView : UIView! = UIView.prepareAutoLayoutView() 124 | open fileprivate(set) var centerContainerView: UIView! = UIView.prepareAutoLayoutView() 125 | open fileprivate(set) var rightContainerView : UIView! = UIView.prepareAutoLayoutView() 126 | 127 | open fileprivate(set) var currentSideMenuState:KVSideMenu.SideMenuState = KVSideMenu.SideMenuState() 128 | 129 | fileprivate var appliedConstraint: NSLayoutConstraint? // may be center, leading, trailling 130 | 131 | fileprivate var panRecognizer: UIPanGestureRecognizer? { 132 | didSet { 133 | panRecognizer?.delegate = self 134 | panRecognizer?.maximumNumberOfTouches = 1 135 | addGestureRecognizer(panRecognizer!) 136 | } 137 | } 138 | 139 | fileprivate var tapRecognizer : UITapGestureRecognizer? { 140 | didSet { 141 | tapRecognizer?.delegate = self 142 | addGestureRecognizer(tapRecognizer!) 143 | } 144 | } 145 | 146 | // MARK: - Initialization 147 | 148 | required public init(superView:UIView!) 149 | { 150 | self.init() 151 | 152 | prepareAutoLayoutView() 153 | backgroundColor = UIColor.clear 154 | superView.addSubview(self) 155 | superView.clipsToBounds = true 156 | 157 | // apply constraints vai oprator overloading. 158 | self +== [.height, .width, .centerX, .centerY] 159 | } 160 | 161 | required public init?(coder aDecoder: NSCoder) { 162 | fatalError("init(coder:) has not been implemented") 163 | } 164 | 165 | fileprivate override init(frame: CGRect) { 166 | super.init(frame: frame) 167 | initialise() 168 | } 169 | 170 | fileprivate func initialise() 171 | { 172 | registerNotifications() 173 | setupGestureRecognizer() 174 | 175 | leftContainerView.backgroundColor = backgroundColor 176 | centerContainerView.backgroundColor = backgroundColor 177 | rightContainerView.backgroundColor = backgroundColor 178 | 179 | // addSubview order maitter for side shadow 180 | addSubview(leftContainerView) 181 | addSubview(rightContainerView) 182 | addSubview(centerContainerView) 183 | 184 | // apply constraints vai oprator overloading. 185 | leftContainerView +== [ .top, .bottom ] 186 | centerContainerView +== [ .top, .bottom, .width, .centerX ] 187 | rightContainerView +== [ .top, .bottom ] 188 | 189 | leftContainerView *== ( .width, KVSideMenuOffsetValueInRatio ) 190 | rightContainerView *== ( .width, KVSideMenuOffsetValueInRatio ) 191 | 192 | leftContainerView |==| ( .trailing, .leading, centerContainerView ) 193 | centerContainerView |==| ( .trailing, .leading, rightContainerView ) 194 | 195 | } 196 | 197 | // MARK: - Deinitialization 198 | 199 | deinit { 200 | unRegisterNotifications() 201 | } 202 | 203 | /// A method that is used to close the side menu if the menu is showed. 204 | @objc open func closeSideMenu() 205 | { 206 | switch (currentSideMenuState) 207 | { 208 | case .left: self.toggleLeftSideMenu() 209 | case .right: self.toggleRightSideMenu() 210 | default: appliedConstraint?.constant = 0 211 | } 212 | 213 | applyAnimations({ 214 | self.centerContainerView.transform = CGAffineTransform.identity 215 | }) 216 | 217 | } 218 | 219 | /** 220 | A method that opens or closes the left side menu & 221 | toggles it's current state either Left or None too. 222 | */ 223 | open func toggleLeftSideMenu() 224 | { 225 | if allowRightPaning { 226 | toggleSideMenu(true) 227 | } 228 | else { 229 | debugPrint("Left SideMenu has beed disable, because leftSideMenuViewController is nil.") 230 | } 231 | 232 | } 233 | 234 | /** 235 | A method that opens or closes the right side menu & 236 | toggles it's current state either Right or None too. 237 | */ 238 | open func toggleRightSideMenu() 239 | { 240 | if allowLeftPaning { 241 | toggleSideMenu(false) 242 | } 243 | else{ 244 | debugPrint("Right SideMenu has beed disable, because rightSideMenuViewController is nil.") 245 | } 246 | } 247 | 248 | } 249 | 250 | // MARK: - Helpper methods to Open & Close the SideMenu 251 | 252 | private extension KVMenuContainerView 253 | { 254 | final func toggleSideMenu(_ isLeft:Bool) 255 | { 256 | let constraintView = isLeft ? leftContainerView : rightContainerView 257 | let attribute = isLeft ? NSLayoutAttribute.leading : NSLayoutAttribute.trailing 258 | 259 | endEditing(true) 260 | 261 | if isLeft { 262 | if (currentSideMenuState == .right) { 263 | closeOpenedSideMenu(rightContainerView, attribute: .trailing) 264 | } 265 | } 266 | else{ 267 | if (currentSideMenuState == .left) { 268 | closeOpenedSideMenu(leftContainerView, attribute: .leading) 269 | } 270 | } 271 | 272 | centerContainerView.accessAppliedConstraintBy(attribute: .centerX) { appliedConstraint in 273 | if appliedConstraint != nil { 274 | // debugPrint("will_Opened_SideMenu") 275 | // debugPrint(self.currentSideMenuState.rawValue) 276 | self.delegate?.willOpenSideMenuView?(self, state: self.currentSideMenuState) 277 | 278 | self.currentSideMenuState = isLeft ? .left : .right 279 | (constraintView?.superview!)! - appliedConstraint! 280 | constraintView! +== attribute 281 | 282 | self.handelTransformAnimations { 283 | // debugPrint(self.currentSideMenuState.rawValue) 284 | // debugPrint("did_Opened_SideMenu") 285 | self.delegate?.didOpenSideMenuView?(self, state: self.currentSideMenuState) 286 | } 287 | } 288 | else { 289 | // debugPrint("will_Closed_SideMenu") 290 | // debugPrint(self.currentSideMenuState.rawValue) 291 | self.delegate?.willCloseSideMenuView?(self, state: self.currentSideMenuState) 292 | 293 | self.closeOpenedSideMenu(constraintView!, attribute: attribute) { 294 | self.applyAnimations { 295 | self.centerContainerView.transform = CGAffineTransform.identity 296 | 297 | // debugPrint("did_Closed_SideMenu") 298 | // debugPrint(self.currentSideMenuState.rawValue) 299 | self.delegate?.didCloseSideMenuView?(self, state: self.currentSideMenuState) 300 | 301 | } 302 | } 303 | } 304 | } 305 | 306 | } 307 | 308 | final func closeOpenedSideMenu(_ view:UIView, attribute attr: NSLayoutAttribute, completion: (() -> Void)? = nil ) 309 | { 310 | view.accessAppliedConstraintBy(attribute: attr, completionHandler: { (appliedConstraint) -> Void in 311 | if appliedConstraint != nil { 312 | self.currentSideMenuState = .none 313 | view.superview! - appliedConstraint! 314 | self.centerContainerView +== [.top, .centerX, .bottom] 315 | if completion == nil { 316 | self.layoutIfNeeded() 317 | self.setNeedsLayout() 318 | }else{ 319 | completion?() 320 | } 321 | } 322 | }) 323 | } 324 | 325 | /// A method that will handel transform & animations too. 326 | final func handelTransformAnimations(_ completionHandler: (() -> Void)? = nil) 327 | { 328 | if self.animationType == KVSideMenu.AnimationType.window { 329 | // update Top And Bottom Pin Constraints Of SideMenu 330 | (centerContainerView +== .bottom).constant = -22.5 331 | (centerContainerView +== .top).constant = 22.5 332 | // this valus is fixed for orientation so try to avoid it 333 | } 334 | 335 | self.applyAnimations { 336 | 337 | if self.animationType == KVSideMenu.AnimationType.folding { 338 | self.applyTransformAnimations(self.centerContainerView, transform_d: self.transformScale.d ) 339 | } 340 | else if self.animationType == KVSideMenu.AnimationType.window { 341 | self.applyTransform3DAnimations(self.centerContainerView, transformRotatingAngle: 22.5) 342 | } 343 | else{ 344 | 345 | } 346 | 347 | completionHandler?() 348 | } 349 | } 350 | 351 | } 352 | 353 | private extension KVMenuContainerView 354 | { 355 | final func registerNotifications() 356 | { 357 | let selector: Selector = #selector(KVMenuContainerView.didReceivedNotification(_:)) 358 | NotificationCenter.default.addObserver(self, selector: selector, name:KVSideMenu.Notifications.toggleLeft, object: nil) 359 | NotificationCenter.default.addObserver(self, selector: selector, name:KVSideMenu.Notifications.toggleRight, object: nil) 360 | NotificationCenter.default.addObserver(self, selector: selector, name:KVSideMenu.Notifications.close, object: nil) 361 | } 362 | 363 | final func unRegisterNotifications() 364 | { 365 | NotificationCenter.default.removeObserver(self, name:KVSideMenu.Notifications.close, object: nil) 366 | NotificationCenter.default.removeObserver(self, name:KVSideMenu.Notifications.toggleLeft, object: nil) 367 | NotificationCenter.default.removeObserver(self, name:KVSideMenu.Notifications.toggleRight, object: nil) 368 | } 369 | 370 | // Must be public or internal but not private other wise app will crashed. 371 | @objc func didReceivedNotification(_ notify:Notification) 372 | { 373 | if (notify.name == KVSideMenu.Notifications.toggleLeft) { 374 | toggleLeftSideMenu() 375 | } else if (notify.name == KVSideMenu.Notifications.toggleRight) { 376 | toggleRightSideMenu() 377 | } else if (notify.name == KVSideMenu.Notifications.close) { 378 | closeSideMenu() 379 | } 380 | else{ 381 | 382 | } 383 | } 384 | 385 | } 386 | 387 | // MARK: - Helpper Methods to Open & Close the SideMenu 388 | 389 | extension KVMenuContainerView: UIGestureRecognizerDelegate 390 | { 391 | // MARK: Gesture recognizer 392 | 393 | fileprivate func setupGestureRecognizer() 394 | { 395 | if allowPanGesture { 396 | panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(KVMenuContainerView.handlePanGesture(_:))) 397 | } 398 | 399 | if allowTapGesture { 400 | tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(KVMenuContainerView.closeSideMenu)) 401 | } 402 | 403 | } 404 | 405 | @objc fileprivate dynamic func handlePanGesture(_ recognizer: UIPanGestureRecognizer) 406 | { 407 | let translation = recognizer.translation(in: recognizer.view) 408 | 409 | switch(recognizer.state) 410 | { 411 | case .began: 412 | switch (currentSideMenuState) 413 | { 414 | case .left: 415 | appliedConstraint = leftContainerView.accessAppliedConstraintBy(attribute: .leading) 416 | case .right: 417 | appliedConstraint = rightContainerView.accessAppliedConstraintBy(attribute: .trailing) 418 | default: 419 | appliedConstraint = centerContainerView.accessAppliedConstraintBy(attribute: .centerX) 420 | } 421 | 422 | case .changed: 423 | 424 | if appliedConstraint != nil { 425 | var xPoint : CGFloat = appliedConstraint!.constant + translation.x 426 | 427 | switch (currentSideMenuState) 428 | { 429 | case .left: 430 | xPoint = max(-leftContainerView.bounds.width, min(CGFloat(xPoint), 0)) 431 | 432 | case .right: 433 | xPoint = max(0, min(CGFloat(xPoint), rightContainerView.bounds.width)) 434 | 435 | default: 436 | 437 | if allowLeftPaning && allowRightPaning { 438 | xPoint = max(-rightContainerView.bounds.width, min(CGFloat(xPoint), leftContainerView.bounds.width)) 439 | } 440 | else if allowLeftPaning { 441 | xPoint = max(-leftContainerView.bounds.width, min(CGFloat(xPoint), 0)) 442 | } 443 | else if allowRightPaning { 444 | xPoint = max(0, min(CGFloat(xPoint), rightContainerView.bounds.width)) 445 | } 446 | else { 447 | xPoint = max(0, min(CGFloat(xPoint), 0)) 448 | } 449 | 450 | } 451 | 452 | if animationType == KVSideMenu.AnimationType.folding 453 | { 454 | let dy = abs(CGFloat(Int(xPoint)))*(1.0 - transformScale.d)/leftContainerView.bounds.width 455 | debugPrint(dy) 456 | 457 | if (currentSideMenuState == .left || currentSideMenuState == .right) { 458 | applyTransformAnimations(centerContainerView, transform_d: min(1.0, transformScale.d + dy)) 459 | } 460 | else{ 461 | applyTransformAnimations(centerContainerView, transform_d: min(1.0, abs(1-dy)) ) 462 | } 463 | } 464 | 465 | self.appliedConstraint?.constant = CGFloat(Int(xPoint)) 466 | recognizer.setTranslation(CGPoint.zero, in: self) 467 | } 468 | 469 | default: 470 | 471 | let constaint = appliedConstraint?.constant ?? 0 472 | 473 | switch (currentSideMenuState) 474 | { 475 | case .left: // Negative value 476 | if abs(constaint) > leftContainerView.bounds.width*thresholdFactor { 477 | self.toggleLeftSideMenu(); 478 | }else{ 479 | // Keep open left SideMenu here 480 | self.appliedConstraint?.constant = 0 481 | self.handelTransformAnimations() 482 | } 483 | 484 | case .right: // Possitive value 485 | if constaint > rightContainerView.bounds.width*thresholdFactor { 486 | self.toggleRightSideMenu(); 487 | }else{ 488 | // Keep open right SideMenu here 489 | self.appliedConstraint?.constant = 0 490 | self.handelTransformAnimations() 491 | } 492 | 493 | default: // None state 494 | if constaint > 0 495 | { 496 | if constaint > leftContainerView.bounds.width*thresholdFactor { 497 | self.toggleLeftSideMenu(); 498 | }else{ 499 | self.closeSideMenu() 500 | } 501 | } 502 | else if constaint < 0 503 | { 504 | if abs(constaint) > rightContainerView.bounds.width*thresholdFactor { 505 | self.toggleRightSideMenu(); 506 | }else{ 507 | self.closeSideMenu() 508 | } 509 | } 510 | } 511 | 512 | appliedConstraint = nil 513 | } 514 | 515 | } 516 | 517 | override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 518 | if gestureRecognizer == panRecognizer { 519 | return (allowPanGesture && (allowLeftPaning || allowRightPaning )) 520 | } 521 | 522 | if gestureRecognizer == tapRecognizer { 523 | return currentSideMenuState != .none && allowTapGesture && self.centerContainerView.frame.contains(gestureRecognizer.location(in: gestureRecognizer.view)) 524 | } 525 | 526 | return false 527 | } 528 | 529 | } 530 | 531 | // MARK: - Helpper methods to apply animation & shadow with SideMenu 532 | 533 | private extension KVMenuContainerView 534 | { 535 | final func applyAnimations(_ completionHandler: (() -> Void)? = nil) 536 | { 537 | // let options : UIViewAnimationOptions = [.AllowUserInteraction, .OverrideInheritedCurve, .LayoutSubviews, .BeginFromCurrentState, .CurveEaseOut] 538 | 539 | let options : UIViewAnimationOptions = [.allowUserInteraction, .layoutSubviews, .beginFromCurrentState, .curveLinear, .curveEaseOut] 540 | let duration = TimeInterval(self.KVSideMenuHideShowDuration) 541 | 542 | UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.95, initialSpringVelocity: 10, options: options, animations: { 543 | self.layoutIfNeeded() 544 | self.setNeedsLayout() 545 | self.setNeedsUpdateConstraints() 546 | self.applyShadow(self.centerContainerView) 547 | completionHandler?() 548 | }) 549 | } 550 | 551 | final func applyTransformAnimations(_ view:UIView!,transform_d:CGFloat) { 552 | view.transform.d = transform_d 553 | } 554 | 555 | final func applyTransform3DAnimations(_ view:UIView!,transformRotatingAngle:CGFloat) 556 | { 557 | let layerTemp : CALayer = view.layer 558 | layerTemp.zPosition = 1000 559 | 560 | var tRotate : CATransform3D = CATransform3DIdentity 561 | tRotate.m34 = 1.0/(500) 562 | 563 | let aXpos: CGFloat = CGFloat(22.5*((currentSideMenuState == .right) ? -1.0 : 1.0)*(Double.pi/180)) 564 | tRotate = CATransform3DRotate(tRotate,aXpos, 0, 1, 0) 565 | layerTemp.transform = tRotate 566 | 567 | } 568 | 569 | // MARK: - Helpper methods to apply shadow with SideMenu 570 | 571 | final func applyShadow(_ shadowView:UIView) 572 | { 573 | let shadowViewLayer : CALayer = shadowView.layer 574 | shadowViewLayer.shadowColor = shadowView.backgroundColor?.cgColor 575 | shadowViewLayer.shadowOpacity = 0.4 576 | shadowViewLayer.shadowRadius = 4.0 577 | shadowViewLayer.rasterizationScale = (self.window?.screen.scale)! 578 | 579 | if (self.currentSideMenuState == .left) { 580 | shadowViewLayer.shadowOffset = CGSize(width: -2, height: 2) 581 | } else if (self.currentSideMenuState == .right){ 582 | shadowViewLayer.shadowOffset = CGSize(width: 0, height: 2) 583 | } else { 584 | shadowViewLayer.shadowRadius = 3 585 | shadowViewLayer.shadowOpacity = 0 586 | shadowViewLayer.shadowOffset = CGSize(width: 0, height: -3) 587 | shadowViewLayer.shadowColor = nil 588 | } 589 | } 590 | 591 | } 592 | -------------------------------------------------------------------------------- /KVRootBaseSideMenu/KVRootBaseSideMenuViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVCustomSegue.swift 3 | // https://github.com/keshavvishwkarma/KVRootBaseSideMenu-Swift.git 4 | // 5 | // Distributed under the MIT License. 6 | // 7 | // Created by Keshav on 7/3/16. 8 | // Copyright © 2016 Keshav. All rights reserved. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | // this software and associated documentation files (the "Software"), to deal in 12 | // the Software without restriction, including without limitation the rights to 13 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | // of the Software, and to permit persons to whom the Software is furnished to do 15 | // so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | import UIKit 30 | 31 | open class KVRootBaseSideMenuViewController: UIViewController 32 | { 33 | fileprivate typealias Key = String 34 | fileprivate typealias Value = UIViewController 35 | 36 | fileprivate var rootObjects: [Key:Value] = [Key:Value](); 37 | 38 | open fileprivate(set) var menuContainerView: KVMenuContainerView? 39 | 40 | /// If **true** then we will always create a new instance of every root viewcontroller. 41 | /// 42 | /// If **false** then we will reuse already created root viewcontroller if exist otherwise create it. 43 | /// By default valus is **false**. 44 | @IBInspectable open var freshRoot : Bool = false 45 | 46 | @IBOutlet open var containerView: UIView? 47 | 48 | open var leftSideMenuViewController: UIViewController? { 49 | didSet { 50 | menuContainerView!.allowRightPaning = leftSideMenuViewController != nil 51 | self.addChildViewControllerOnContainerView(leftSideMenuViewController, containerView: menuContainerView!.leftContainerView) 52 | } 53 | } 54 | 55 | open var rightSideMenuViewController: UIViewController? { 56 | didSet{ 57 | menuContainerView!.allowLeftPaning = rightSideMenuViewController != nil 58 | self.addChildViewControllerOnContainerView(rightSideMenuViewController, containerView: menuContainerView!.rightContainerView) 59 | } 60 | } 61 | 62 | fileprivate var visibleRootViewController: UIViewController? { 63 | didSet 64 | { 65 | if oldValue == nil { 66 | self.addChildViewControllerOnContainerView(self.visibleRootViewController, containerView:self.menuContainerView?.centerContainerView) 67 | } 68 | else if oldValue != visibleRootViewController 69 | { 70 | oldValue?.willMove(toParentViewController: nil) 71 | UIView.animate(withDuration: 0, animations: { }, completion: { _ in 72 | DispatchQueue.main.async(execute: { 73 | oldValue?.view.removeFromSuperview() 74 | oldValue?.didMove(toParentViewController: nil) 75 | oldValue?.removeFromParentViewController() 76 | self.addChildViewControllerOnContainerView(self.visibleRootViewController, containerView:self.menuContainerView?.centerContainerView) 77 | 78 | }) 79 | }) 80 | } 81 | else{ 82 | debugPrint("both objects are same.") 83 | } 84 | 85 | } 86 | } 87 | 88 | override open func loadView() { 89 | super.loadView() 90 | self.menuContainerView = KVMenuContainerView(superView: (containerView == nil) ? self.view : containerView); 91 | } 92 | 93 | ///Returns a Boolean value that indicates, either the side menu is showed or closed. 94 | open func isSideMenuOpen () -> Bool { 95 | let sieMenuOpen = !(menuContainerView!.currentSideMenuState == .none) 96 | return sieMenuOpen 97 | } 98 | 99 | override open func viewWillAppear(_ animated: Bool) { 100 | super.viewWillAppear(animated) 101 | 102 | self.setNeedsStatusBarAppearanceUpdate() 103 | 104 | // Listen for changes to keyboard visibility so that we can adjust the text view accordingly. 105 | let notificationCenter = NotificationCenter.default 106 | notificationCenter.addObserver(self, selector: #selector(KVRootBaseSideMenuViewController.handleKeyboardNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) 107 | notificationCenter.addObserver(self, selector: #selector(KVRootBaseSideMenuViewController.handleKeyboardNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) 108 | } 109 | 110 | override open func viewDidDisappear(_ animated: Bool) { 111 | super.viewDidDisappear(animated) 112 | 113 | let notificationCenter = NotificationCenter.default 114 | notificationCenter.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) 115 | notificationCenter.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) 116 | } 117 | 118 | 119 | /// To switch the root of side menu controller. 120 | override open func changeSideMenuViewControllerRoot(_ rootIdentifier:String) 121 | { 122 | if shouldPerformSegue(withIdentifier: rootIdentifier, sender: self) { 123 | performSegue(withIdentifier: rootIdentifier, sender: self) 124 | } 125 | } 126 | 127 | override open func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { 128 | let shouldPerformSegue = super.shouldPerformSegue(withIdentifier: identifier, sender: sender); 129 | if (shouldPerformSegue) 130 | { 131 | // If root view controller, already exist in the rootObjects list then change to root only. 132 | // and sugue should be ignored 133 | if let value = rootObjects[identifier] { 134 | visibleRootViewController = value 135 | return false 136 | } 137 | 138 | // If root view controller, does not exist in the rootObjects list, that means 139 | // The segue should be performed to fetch destinationViewController obejct. 140 | // If sender is KVCustomSegue that means viewcontroller is first time going to be initialise. 141 | if (sender is KVCustomSegue) { 142 | setUpSideMenuRootBySegue((sender as! KVCustomSegue)) 143 | } 144 | } 145 | 146 | return shouldPerformSegue; 147 | } 148 | 149 | } 150 | 151 | private extension KVRootBaseSideMenuViewController 152 | { 153 | func setUpSideMenuRootBySegue(_ segue:KVCustomSegue) 154 | { 155 | if ( self == segue.source ) 156 | { 157 | // If freshRoot is true means allways prefere feresh root then we will always create a new instance for everry root viewcontrollers. 158 | // If freshRoot is false then we will reuse already created root view controller 159 | 160 | if freshRoot == false { 161 | if !(rootObjects.keys.contains(segue.identifier!)) { 162 | rootObjects[segue.identifier!] = segue.destination 163 | } 164 | visibleRootViewController = rootObjects[segue.identifier!] 165 | } 166 | else{ 167 | visibleRootViewController = segue.destination 168 | } 169 | } 170 | else { 171 | debugPrint("Both objects are distinct \(self), \(segue.source)") 172 | } 173 | } 174 | 175 | 176 | // MARK: Keyboard Event Notifications 177 | 178 | @objc func handleKeyboardNotification(_ notification: Notification) { 179 | let userInfo = notification.userInfo! 180 | 181 | // Get information about the animation. 182 | let animationDuration: TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue 183 | 184 | let rawAnimationCurveValue = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).uintValue 185 | let animationCurve = UIViewAnimationOptions(rawValue: rawAnimationCurveValue) 186 | 187 | // Convert the keyboard frame from screen to view coordinates. 188 | let keyboardScreenBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue 189 | let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue 190 | 191 | let keyboardViewBeginFrame = view.convert(keyboardScreenBeginFrame, from: view.window) 192 | let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window) 193 | 194 | // Determine how far the keyboard has moved up or down. 195 | let originDelta = keyboardViewEndFrame.origin.y - keyboardViewBeginFrame.origin.y 196 | 197 | // Inform the view that its the layout should be updated. 198 | (menuContainerView!.leftContainerView <- .bottom)?.constant += originDelta 199 | (menuContainerView!.centerContainerView <- .bottom)?.constant += originDelta 200 | (menuContainerView!.rightContainerView <- .bottom)?.constant += originDelta 201 | 202 | menuContainerView!.layoutIfNeeded() 203 | // Animate updating the view's layout by calling layoutIfNeeded inside a UIView animation block. 204 | let animationOptions: UIViewAnimationOptions = [animationCurve, .beginFromCurrentState] 205 | UIView.animate(withDuration: animationDuration, delay: 0, options: animationOptions, animations: { 206 | self.view.layoutIfNeeded() 207 | }, completion: nil) 208 | } 209 | } 210 | 211 | public extension KVRootBaseSideMenuViewController { 212 | 213 | // MARK: To access the currently visible ViewController on the view of KVRootBaseSideMenuViewController. 214 | 215 | public func visibleViewController() -> UIViewController? { 216 | 217 | if visibleRootViewController is UINavigationController { 218 | return (visibleRootViewController as! UINavigationController).topViewController 219 | // return (visibleRootViewController as! UINavigationController).visibleViewController 220 | } 221 | else { 222 | return visibleRootViewController 223 | } 224 | } 225 | 226 | } 227 | 228 | // MARK: 229 | extension UIViewController 230 | { 231 | @objc public func sideMenuViewController() -> KVRootBaseSideMenuViewController? 232 | { 233 | var viewController:UIViewController? = ( self.parent != nil) ? self.parent : self.presentingViewController; 234 | 235 | while (!((viewController == nil ) || (viewController is KVRootBaseSideMenuViewController))) { 236 | viewController = ( viewController!.parent != nil) ? viewController!.parent : viewController!.presentingViewController; 237 | } 238 | 239 | return (viewController as! KVRootBaseSideMenuViewController) 240 | } 241 | 242 | /// To switch the root of side menu controller from any view controller. 243 | @objc public func changeSideMenuViewControllerRoot(_ rootIdentifier:String) 244 | { 245 | if let sideMenuViewController = sideMenuViewController() { 246 | sideMenuViewController.changeSideMenuViewControllerRoot(rootIdentifier) 247 | } 248 | } 249 | 250 | } 251 | 252 | public extension UIViewController { 253 | 254 | public func addChildViewControllerOnContainerView(_ childViewController: UIViewController!, containerView: UIView!) 255 | { 256 | if childViewController != nil && containerView != nil 257 | { 258 | childViewController.view.frame = containerView.bounds 259 | self.addChildViewController(childViewController) 260 | containerView.addSubview(childViewController.view) 261 | childViewController.didMove(toParentViewController: self) 262 | containerView.bringSubview(toFront: childViewController.view) 263 | 264 | if (containerView.translatesAutoresizingMaskIntoConstraints) { 265 | childViewController.view.autoresizingMask = [.flexibleWidth,.flexibleHeight] 266 | } else { 267 | let child = childViewController.view 268 | child!.prepareAutoLayoutView() 269 | 270 | // Apply Equal relation constrains to its parent view. 271 | child! +== [.centerX, .centerY, .height, .width] 272 | } 273 | } 274 | 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /KVRootBaseSideMenuTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /KVRootBaseSideMenuTests/KVRootBaseSideMenuTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // KVRootBaseSideMenuTests.swift 3 | // KVRootBaseSideMenuTests 4 | // 5 | // Created by Keshav on 12/6/16. 6 | // Copyright © 2016 com.keshav. KVRootBaseSideMenu. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import KVRootBaseSideMenu 11 | 12 | class KVRootBaseSideMenuTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Keshav Vishwkarma 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KVRootBaseSideMenu-Swift 2 | 3 | It's a root base side menu with autolayout for iOS applications & It is also written in pure swift. 4 | ### Demo 5 | [![KVRootBaseSideMenu-Swift](http://img.youtube.com/vi/104QJ6Nn77A/0.jpg)](http://www.youtube.com/watch?v=104QJ6Nn77A) 6 | 7 | ### Features 8 | - [x] Highly customizable & easy to use. 9 | - [x] You can add this side menu in a view of viewCintroller Or any specific subview of viewcontroller. 10 | - [x] Support both left & right side menu. 11 | - [x] Support finger touch to open or close both side menu 12 | - [x] Automatic orientation support because of autolayout that we used. 13 | - [x] Automatically manage Left, right or left & right side menu sliding & toggle functionality to open or close. 14 | - [x] Complete example 15 | - [x] Carthage Support 16 | 17 | ### TO DO 18 | - [ ] By supporting @IBInspectable, the class properties can be exposed in the Interface Builder 19 | - [ ] Advance example. 20 | 21 | ### Requirements 22 | * iOS 8+ (compatible with iOS 8) 23 | * Xcode 8.0 24 | 25 | Usage 26 | -------------- 27 | #### `Step 1.` 28 | Prepare `SideMenuViewController`, either `LeftViewController` or `RightViewController` or both. 29 | - Create a subclass of **KVRootBaseSideMenuViewController** called SideMenuViewController. 30 | - Create LeftViewController Or RightViewController Or both class subclassing from UIViewController. 31 | ``` 32 | class SideMenuViewController: KVRootBaseSideMenuViewController { 33 | 34 | } 35 | class LeftViewController: UIViewController { 36 | 37 | } 38 | class RightViewController: UIViewController { 39 | 40 | } 41 | ``` 42 | - In Storyboard, Drag three view controllers from the Object library to the storyboard canvas and give them class name in the Attributes inspector for the scenes. one is `SideMenuViewController ` second is `LeftViewController` & third is `RightViewController`. 43 | 44 | #### `Step 2.` 45 | - Prepare roots(options available in left and/or Right side menu) & roots identifiers and [Connect](#Connect_Roots) all the roots from side menu view controller. 46 | 47 | - In storyboard, drag view controller objects from the Object library to the scene, create a custom view controller class. Specify this class as the custom class in the Attributes inspector for the scene. 48 | 49 | - Now define the roots Identifier, in this example I'm doing as - 50 | ``` 51 | public extension KVSideMenu 52 | { 53 | // Here define the roots identifier of side menus that must be connected 54 | // from KVRootBaseSideMenuViewController or any derived class of it 55 | // In Storyboard using KVCustomSegue 56 | 57 | static public let leftSideViewController = "LeftSideViewController" 58 | static public let rightSideViewController = "RightSideViewController" 59 | 60 | struct RootsIdentifiers 61 | { 62 | static public let initialViewController = "SecondViewController" 63 | 64 | // All roots viewcontrollers 65 | static public let firstViewController = "FirstViewController" 66 | static public let secondViewController = "SecondViewController" 67 | } 68 | 69 | } 70 | ``` 71 | 72 | How to connect roots from side menu view controller 73 | ----- 74 | - You need to create a segue from the `SideMenuViewController` itself to the destination root viewController. You must do this for each root viewController and give them appropriate `identifiers` and give them ’Segue Class’ i.e. `KVCustomSegue` 75 | 76 | #### `Step 3.` 77 | 78 | - To enable left or right or both SideMenu, you must assign a `leftSideMenuViewController` or `rightSideMenuViewController` or both at any moment. In this example I'm doing as - 79 | ``` 80 | class SideMenuViewController: KVRootBaseSideMenuViewController 81 | { 82 | override func viewDidLoad() { 83 | super.viewDidLoad() 84 | 85 | // Configure The Side Menu 86 | leftSideMenuViewController = self.storyboard?.instantiateViewControllerWithIdentifier(KVSideMenu.leftSideViewController) 87 | rightSideMenuViewController = self.storyboard?.instantiateViewControllerWithIdentifier(KVSideMenu.rightSideViewController) 88 | 89 | // Set default root 90 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.initialViewController) 91 | } 92 | 93 | } 94 | ``` 95 | Now side menu setup is done. 96 | 97 | #### To Change Root call - 98 | `public func changeSideMenuViewControllerRoot(rootIdentifier:String) ` 99 | 100 | #### To Toggle Side Menu Post notification 101 | `Post notification by name KVSideMenu.Notifications.toggleRight Or KVSideMenu.Notifications.toggleLeft ` 102 | 103 | Ex- 104 | 105 | ``` 106 | class LeftSideViewController: UIViewController 107 | { 108 | @IBAction func moveToFirstViewControllerButton(sender: AnyObject) { 109 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.firstViewController) 110 | NSNotificationCenter.defaultCenter().postNotificationName(KVSideMenu.Notifications.toggleLeft, object: self) 111 | } 112 | 113 | @IBAction func moveToSecondViewControllerButton(sender: AnyObject) { 114 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.secondViewController) 115 | NSNotificationCenter.defaultCenter().postNotificationName(KVSideMenu.Notifications.toggleLeft, object: self) 116 | } 117 | 118 | } 119 | 120 | class RightSideViewController: UIViewController 121 | { 122 | @IBAction func moveToFirstViewControllerButton(sender: AnyObject) { 123 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.firstViewController) 124 | NSNotificationCenter.defaultCenter().postNotificationName(KVSideMenu.Notifications.toggleRight, object: nil) 125 | } 126 | 127 | @IBAction func moveToSecondViewControllerButton(sender: AnyObject) { 128 | self.changeSideMenuViewControllerRoot(KVSideMenu.RootsIdentifiers.secondViewController) 129 | NSNotificationCenter.defaultCenter().postNotificationName(KVSideMenu.Notifications.toggleRight, object: nil) 130 | } 131 | 132 | } 133 | 134 | ``` 135 | ## License 136 | 137 | KVRootBaseSideMenu-Swift is released under the MIT license. See the LICENSE for details. 138 | 139 | ## Contributions 140 | 141 | Any contribution is more than welcome! You can contribute through pull requests and issues on GitHub. 142 | 143 | ## Author 144 | 145 | Keshav Vishwkarma, If you wish to contact me, email at: keshavvbe@gmail.com 146 | -------------------------------------------------------------------------------- /Supporting Files/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Supporting Files/KVRootBaseSideMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // KVRootBaseSideMenu.h 3 | // KVRootBaseSideMenu 4 | // 5 | // Created by Keshav on 12/6/16. 6 | // Copyright © 2016 com.keshav. KVRootBaseSideMenu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for KVRootBaseSideMenu. 12 | FOUNDATION_EXPORT double KVRootBaseSideMenuVersionNumber; 13 | 14 | //! Project version string for KVRootBaseSideMenu. 15 | FOUNDATION_EXPORT const unsigned char KVRootBaseSideMenuVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | --------------------------------------------------------------------------------