├── .DS_Store ├── .gitignore ├── AirbnbViewController-Sample ├── .DS_Store ├── AirbnbViewController-Sample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── AirbnbViewController-Sample │ ├── AirbnbViewController-Sample-Bridging-Header.h │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-Small@2x.png │ │ │ └── Icon-Small@3x.png │ ├── Info.plist │ ├── MenuViewController.swift │ └── ViewController.swift └── AirbnbViewController-SampleTests │ ├── AirbnbViewController_SampleTests.swift │ └── Info.plist ├── AirbnbViewController.podspec ├── AirbnbViewController ├── AirbnbHelper.h ├── AirbnbHelper.m ├── AirbnbSessionView.swift └── AirbnbViewController.swift ├── AirbnbViewControllerTests ├── AirbnbViewControllerTests.swift └── Info.plist ├── Assets └── demo.gif ├── LICENSE └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/.DS_Store -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6ECE0CD91AB87C8600C054DD /* AirbnbSessionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ECE0CD71AB87C8600C054DD /* AirbnbSessionView.swift */; }; 11 | 6ECE0CDA1AB87C8600C054DD /* AirbnbViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ECE0CD81AB87C8600C054DD /* AirbnbViewController.swift */; }; 12 | 6ECE0CE01AB87F1C00C054DD /* AirbnbHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 6ECE0CDE1AB87F1C00C054DD /* AirbnbHelper.m */; }; 13 | 6ED29F9D1A77BA85005675F8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ED29F9C1A77BA85005675F8 /* AppDelegate.swift */; }; 14 | 6ED29F9F1A77BA85005675F8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ED29F9E1A77BA85005675F8 /* ViewController.swift */; }; 15 | 6ED29FA41A77BA85005675F8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6ED29FA31A77BA85005675F8 /* Images.xcassets */; }; 16 | 6ED29FA71A77BA85005675F8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6ED29FA51A77BA85005675F8 /* LaunchScreen.xib */; }; 17 | 6ED29FB31A77BA85005675F8 /* AirbnbViewController_SampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ED29FB21A77BA85005675F8 /* AirbnbViewController_SampleTests.swift */; }; 18 | 6ED29FC71A77C1FA005675F8 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ED29FC61A77C1FA005675F8 /* MenuViewController.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 6ED29FAD1A77BA85005675F8 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 6ED29F8F1A77BA85005675F8 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 6ED29F961A77BA85005675F8; 27 | remoteInfo = "AirbnbViewController-Sample"; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 6ECE0CD71AB87C8600C054DD /* AirbnbSessionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AirbnbSessionView.swift; path = ../../AirbnbViewController/AirbnbSessionView.swift; sourceTree = ""; }; 33 | 6ECE0CD81AB87C8600C054DD /* AirbnbViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AirbnbViewController.swift; path = ../../AirbnbViewController/AirbnbViewController.swift; sourceTree = ""; }; 34 | 6ECE0CDD1AB87F1C00C054DD /* AirbnbHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AirbnbHelper.h; path = ../../AirbnbViewController/AirbnbHelper.h; sourceTree = ""; }; 35 | 6ECE0CDE1AB87F1C00C054DD /* AirbnbHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AirbnbHelper.m; path = ../../AirbnbViewController/AirbnbHelper.m; sourceTree = ""; }; 36 | 6ED29F971A77BA85005675F8 /* AirbnbViewController-Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AirbnbViewController-Sample.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 6ED29F9B1A77BA85005675F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 6ED29F9C1A77BA85005675F8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 39 | 6ED29F9E1A77BA85005675F8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 40 | 6ED29FA31A77BA85005675F8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 41 | 6ED29FA61A77BA85005675F8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 42 | 6ED29FAC1A77BA85005675F8 /* AirbnbViewController-SampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AirbnbViewController-SampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 6ED29FB11A77BA85005675F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | 6ED29FB21A77BA85005675F8 /* AirbnbViewController_SampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirbnbViewController_SampleTests.swift; sourceTree = ""; }; 45 | 6ED29FC51A77C0F7005675F8 /* AirbnbViewController-Sample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AirbnbViewController-Sample-Bridging-Header.h"; sourceTree = ""; }; 46 | 6ED29FC61A77C1FA005675F8 /* MenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuViewController.swift; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | 6ED29F941A77BA85005675F8 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | 6ED29FA91A77BA85005675F8 /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | 6ECE0CDB1AB87C8E00C054DD /* AirbnbViewController */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 6ECE0CDD1AB87F1C00C054DD /* AirbnbHelper.h */, 71 | 6ECE0CDE1AB87F1C00C054DD /* AirbnbHelper.m */, 72 | 6ECE0CD71AB87C8600C054DD /* AirbnbSessionView.swift */, 73 | 6ECE0CD81AB87C8600C054DD /* AirbnbViewController.swift */, 74 | ); 75 | name = AirbnbViewController; 76 | sourceTree = ""; 77 | }; 78 | 6ED29F8E1A77BA85005675F8 = { 79 | isa = PBXGroup; 80 | children = ( 81 | 6ED29F991A77BA85005675F8 /* AirbnbViewController-Sample */, 82 | 6ED29FAF1A77BA85005675F8 /* AirbnbViewController-SampleTests */, 83 | 6ED29F981A77BA85005675F8 /* Products */, 84 | ); 85 | sourceTree = ""; 86 | }; 87 | 6ED29F981A77BA85005675F8 /* Products */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 6ED29F971A77BA85005675F8 /* AirbnbViewController-Sample.app */, 91 | 6ED29FAC1A77BA85005675F8 /* AirbnbViewController-SampleTests.xctest */, 92 | ); 93 | name = Products; 94 | sourceTree = ""; 95 | }; 96 | 6ED29F991A77BA85005675F8 /* AirbnbViewController-Sample */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 6ECE0CDB1AB87C8E00C054DD /* AirbnbViewController */, 100 | 6ED29F9C1A77BA85005675F8 /* AppDelegate.swift */, 101 | 6ED29F9E1A77BA85005675F8 /* ViewController.swift */, 102 | 6ED29FC61A77C1FA005675F8 /* MenuViewController.swift */, 103 | 6ED29FA31A77BA85005675F8 /* Images.xcassets */, 104 | 6ED29FA51A77BA85005675F8 /* LaunchScreen.xib */, 105 | 6ED29F9A1A77BA85005675F8 /* Supporting Files */, 106 | ); 107 | path = "AirbnbViewController-Sample"; 108 | sourceTree = ""; 109 | }; 110 | 6ED29F9A1A77BA85005675F8 /* Supporting Files */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 6ED29F9B1A77BA85005675F8 /* Info.plist */, 114 | 6ED29FC51A77C0F7005675F8 /* AirbnbViewController-Sample-Bridging-Header.h */, 115 | ); 116 | name = "Supporting Files"; 117 | sourceTree = ""; 118 | }; 119 | 6ED29FAF1A77BA85005675F8 /* AirbnbViewController-SampleTests */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 6ED29FB21A77BA85005675F8 /* AirbnbViewController_SampleTests.swift */, 123 | 6ED29FB01A77BA85005675F8 /* Supporting Files */, 124 | ); 125 | path = "AirbnbViewController-SampleTests"; 126 | sourceTree = ""; 127 | }; 128 | 6ED29FB01A77BA85005675F8 /* Supporting Files */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 6ED29FB11A77BA85005675F8 /* Info.plist */, 132 | ); 133 | name = "Supporting Files"; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXNativeTarget section */ 139 | 6ED29F961A77BA85005675F8 /* AirbnbViewController-Sample */ = { 140 | isa = PBXNativeTarget; 141 | buildConfigurationList = 6ED29FB61A77BA85005675F8 /* Build configuration list for PBXNativeTarget "AirbnbViewController-Sample" */; 142 | buildPhases = ( 143 | 6ED29F931A77BA85005675F8 /* Sources */, 144 | 6ED29F941A77BA85005675F8 /* Frameworks */, 145 | 6ED29F951A77BA85005675F8 /* Resources */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | ); 151 | name = "AirbnbViewController-Sample"; 152 | productName = "AirbnbViewController-Sample"; 153 | productReference = 6ED29F971A77BA85005675F8 /* AirbnbViewController-Sample.app */; 154 | productType = "com.apple.product-type.application"; 155 | }; 156 | 6ED29FAB1A77BA85005675F8 /* AirbnbViewController-SampleTests */ = { 157 | isa = PBXNativeTarget; 158 | buildConfigurationList = 6ED29FB91A77BA85005675F8 /* Build configuration list for PBXNativeTarget "AirbnbViewController-SampleTests" */; 159 | buildPhases = ( 160 | 6ED29FA81A77BA85005675F8 /* Sources */, 161 | 6ED29FA91A77BA85005675F8 /* Frameworks */, 162 | 6ED29FAA1A77BA85005675F8 /* Resources */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | 6ED29FAE1A77BA85005675F8 /* PBXTargetDependency */, 168 | ); 169 | name = "AirbnbViewController-SampleTests"; 170 | productName = "AirbnbViewController-SampleTests"; 171 | productReference = 6ED29FAC1A77BA85005675F8 /* AirbnbViewController-SampleTests.xctest */; 172 | productType = "com.apple.product-type.bundle.unit-test"; 173 | }; 174 | /* End PBXNativeTarget section */ 175 | 176 | /* Begin PBXProject section */ 177 | 6ED29F8F1A77BA85005675F8 /* Project object */ = { 178 | isa = PBXProject; 179 | attributes = { 180 | LastUpgradeCheck = 0610; 181 | ORGANIZATIONNAME = pixyzehn; 182 | TargetAttributes = { 183 | 6ED29F961A77BA85005675F8 = { 184 | CreatedOnToolsVersion = 6.1.1; 185 | }; 186 | 6ED29FAB1A77BA85005675F8 = { 187 | CreatedOnToolsVersion = 6.1.1; 188 | TestTargetID = 6ED29F961A77BA85005675F8; 189 | }; 190 | }; 191 | }; 192 | buildConfigurationList = 6ED29F921A77BA85005675F8 /* Build configuration list for PBXProject "AirbnbViewController-Sample" */; 193 | compatibilityVersion = "Xcode 3.2"; 194 | developmentRegion = English; 195 | hasScannedForEncodings = 0; 196 | knownRegions = ( 197 | en, 198 | Base, 199 | ); 200 | mainGroup = 6ED29F8E1A77BA85005675F8; 201 | productRefGroup = 6ED29F981A77BA85005675F8 /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 6ED29F961A77BA85005675F8 /* AirbnbViewController-Sample */, 206 | 6ED29FAB1A77BA85005675F8 /* AirbnbViewController-SampleTests */, 207 | ); 208 | }; 209 | /* End PBXProject section */ 210 | 211 | /* Begin PBXResourcesBuildPhase section */ 212 | 6ED29F951A77BA85005675F8 /* Resources */ = { 213 | isa = PBXResourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 6ED29FA71A77BA85005675F8 /* LaunchScreen.xib in Resources */, 217 | 6ED29FA41A77BA85005675F8 /* Images.xcassets in Resources */, 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | 6ED29FAA1A77BA85005675F8 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXSourcesBuildPhase section */ 231 | 6ED29F931A77BA85005675F8 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 6ECE0CE01AB87F1C00C054DD /* AirbnbHelper.m in Sources */, 236 | 6ECE0CD91AB87C8600C054DD /* AirbnbSessionView.swift in Sources */, 237 | 6ECE0CDA1AB87C8600C054DD /* AirbnbViewController.swift in Sources */, 238 | 6ED29F9F1A77BA85005675F8 /* ViewController.swift in Sources */, 239 | 6ED29FC71A77C1FA005675F8 /* MenuViewController.swift in Sources */, 240 | 6ED29F9D1A77BA85005675F8 /* AppDelegate.swift in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | 6ED29FA81A77BA85005675F8 /* Sources */ = { 245 | isa = PBXSourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 6ED29FB31A77BA85005675F8 /* AirbnbViewController_SampleTests.swift in Sources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXSourcesBuildPhase section */ 253 | 254 | /* Begin PBXTargetDependency section */ 255 | 6ED29FAE1A77BA85005675F8 /* PBXTargetDependency */ = { 256 | isa = PBXTargetDependency; 257 | target = 6ED29F961A77BA85005675F8 /* AirbnbViewController-Sample */; 258 | targetProxy = 6ED29FAD1A77BA85005675F8 /* PBXContainerItemProxy */; 259 | }; 260 | /* End PBXTargetDependency section */ 261 | 262 | /* Begin PBXVariantGroup section */ 263 | 6ED29FA51A77BA85005675F8 /* LaunchScreen.xib */ = { 264 | isa = PBXVariantGroup; 265 | children = ( 266 | 6ED29FA61A77BA85005675F8 /* Base */, 267 | ); 268 | name = LaunchScreen.xib; 269 | sourceTree = ""; 270 | }; 271 | /* End PBXVariantGroup section */ 272 | 273 | /* Begin XCBuildConfiguration section */ 274 | 6ED29FB41A77BA85005675F8 /* Debug */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | ALWAYS_SEARCH_USER_PATHS = NO; 278 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 279 | CLANG_CXX_LIBRARY = "libc++"; 280 | CLANG_ENABLE_MODULES = YES; 281 | CLANG_ENABLE_OBJC_ARC = YES; 282 | CLANG_WARN_BOOL_CONVERSION = YES; 283 | CLANG_WARN_CONSTANT_CONVERSION = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_EMPTY_BODY = YES; 286 | CLANG_WARN_ENUM_CONVERSION = YES; 287 | CLANG_WARN_INT_CONVERSION = YES; 288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | ENABLE_STRICT_OBJC_MSGSEND = YES; 294 | GCC_C_LANGUAGE_STANDARD = gnu99; 295 | GCC_DYNAMIC_NO_PIC = NO; 296 | GCC_OPTIMIZATION_LEVEL = 0; 297 | GCC_PREPROCESSOR_DEFINITIONS = ( 298 | "DEBUG=1", 299 | "$(inherited)", 300 | ); 301 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 302 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 303 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 304 | GCC_WARN_UNDECLARED_SELECTOR = YES; 305 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 306 | GCC_WARN_UNUSED_FUNCTION = YES; 307 | GCC_WARN_UNUSED_VARIABLE = YES; 308 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 309 | MTL_ENABLE_DEBUG_INFO = YES; 310 | ONLY_ACTIVE_ARCH = YES; 311 | SDKROOT = iphoneos; 312 | SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PROJECT)/AirbnbViewController-Sample-Bridging-Header.h"; 313 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 314 | }; 315 | name = Debug; 316 | }; 317 | 6ED29FB51A77BA85005675F8 /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ALWAYS_SEARCH_USER_PATHS = NO; 321 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 322 | CLANG_CXX_LIBRARY = "libc++"; 323 | CLANG_ENABLE_MODULES = YES; 324 | CLANG_ENABLE_OBJC_ARC = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_CONSTANT_CONVERSION = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_EMPTY_BODY = YES; 329 | CLANG_WARN_ENUM_CONVERSION = YES; 330 | CLANG_WARN_INT_CONVERSION = YES; 331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 332 | CLANG_WARN_UNREACHABLE_CODE = YES; 333 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 334 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 335 | COPY_PHASE_STRIP = YES; 336 | ENABLE_NS_ASSERTIONS = NO; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 340 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 341 | GCC_WARN_UNDECLARED_SELECTOR = YES; 342 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 343 | GCC_WARN_UNUSED_FUNCTION = YES; 344 | GCC_WARN_UNUSED_VARIABLE = YES; 345 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 346 | MTL_ENABLE_DEBUG_INFO = NO; 347 | SDKROOT = iphoneos; 348 | SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/$(PROJECT)/AirbnbViewController-Sample-Bridging-Header.h"; 349 | VALIDATE_PRODUCT = YES; 350 | }; 351 | name = Release; 352 | }; 353 | 6ED29FB71A77BA85005675F8 /* Debug */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 357 | INFOPLIST_FILE = "AirbnbViewController-Sample/Info.plist"; 358 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 359 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 360 | PRODUCT_NAME = "$(TARGET_NAME)"; 361 | }; 362 | name = Debug; 363 | }; 364 | 6ED29FB81A77BA85005675F8 /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 368 | INFOPLIST_FILE = "AirbnbViewController-Sample/Info.plist"; 369 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 370 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 371 | PRODUCT_NAME = "$(TARGET_NAME)"; 372 | }; 373 | name = Release; 374 | }; 375 | 6ED29FBA1A77BA85005675F8 /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | BUNDLE_LOADER = "$(TEST_HOST)"; 379 | FRAMEWORK_SEARCH_PATHS = ( 380 | "$(SDKROOT)/Developer/Library/Frameworks", 381 | "$(inherited)", 382 | ); 383 | GCC_PREPROCESSOR_DEFINITIONS = ( 384 | "DEBUG=1", 385 | "$(inherited)", 386 | ); 387 | INFOPLIST_FILE = "AirbnbViewController-SampleTests/Info.plist"; 388 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 389 | PRODUCT_NAME = "$(TARGET_NAME)"; 390 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AirbnbViewController-Sample.app/AirbnbViewController-Sample"; 391 | }; 392 | name = Debug; 393 | }; 394 | 6ED29FBB1A77BA85005675F8 /* Release */ = { 395 | isa = XCBuildConfiguration; 396 | buildSettings = { 397 | BUNDLE_LOADER = "$(TEST_HOST)"; 398 | FRAMEWORK_SEARCH_PATHS = ( 399 | "$(SDKROOT)/Developer/Library/Frameworks", 400 | "$(inherited)", 401 | ); 402 | INFOPLIST_FILE = "AirbnbViewController-SampleTests/Info.plist"; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 404 | PRODUCT_NAME = "$(TARGET_NAME)"; 405 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AirbnbViewController-Sample.app/AirbnbViewController-Sample"; 406 | }; 407 | name = Release; 408 | }; 409 | /* End XCBuildConfiguration section */ 410 | 411 | /* Begin XCConfigurationList section */ 412 | 6ED29F921A77BA85005675F8 /* Build configuration list for PBXProject "AirbnbViewController-Sample" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | 6ED29FB41A77BA85005675F8 /* Debug */, 416 | 6ED29FB51A77BA85005675F8 /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | 6ED29FB61A77BA85005675F8 /* Build configuration list for PBXNativeTarget "AirbnbViewController-Sample" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | 6ED29FB71A77BA85005675F8 /* Debug */, 425 | 6ED29FB81A77BA85005675F8 /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | 6ED29FB91A77BA85005675F8 /* Build configuration list for PBXNativeTarget "AirbnbViewController-SampleTests" */ = { 431 | isa = XCConfigurationList; 432 | buildConfigurations = ( 433 | 6ED29FBA1A77BA85005675F8 /* Debug */, 434 | 6ED29FBB1A77BA85005675F8 /* Release */, 435 | ); 436 | defaultConfigurationIsVisible = 0; 437 | defaultConfigurationName = Release; 438 | }; 439 | /* End XCConfigurationList section */ 440 | }; 441 | rootObject = 6ED29F8F1A77BA85005675F8 /* Project object */; 442 | } 443 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/AirbnbViewController-Sample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // AirbnbViewController-Sample-Bridging-Header.h 3 | // AirbnbViewController-Sample 4 | // 5 | // Created by pixyzehn on 1/27/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | #import "AirbnbHelper.h" -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AirbnbViewController-Sample 4 | // 5 | // Created by pixyzehn on 1/27/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 17 | // Override point for customization after application launch. 18 | 19 | self.window = UIWindow(frame: UIScreen.mainScreen().bounds) 20 | 21 | let viewController: ViewController = ViewController() 22 | let controller: UINavigationController = UINavigationController(rootViewController: viewController) 23 | viewController.view.backgroundColor = UIColor(red:0, green:0.23, blue:0.36, alpha:1) 24 | 25 | let menuController: MenuViewController = MenuViewController(viewController: controller, atIndexPath: NSIndexPath(forRow: 0, inSection: 0)) 26 | 27 | self.window!.rootViewController = menuController 28 | self.window!.makeKeyAndVisible() 29 | 30 | return true 31 | } 32 | 33 | func applicationWillResignActive(application: UIApplication) { 34 | // 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. 35 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 36 | } 37 | 38 | func applicationDidEnterBackground(application: UIApplication) { 39 | // 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. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | func applicationWillEnterForeground(application: UIApplication) { 44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 45 | } 46 | 47 | func applicationDidBecomeActive(application: UIApplication) { 48 | // 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. 49 | } 50 | 51 | func applicationWillTerminate(application: UIApplication) { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/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 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Small@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Small@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/AirbnbViewController-Sample/AirbnbViewController-Sample/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | pixyzehn.$(PRODUCT_NAME:rfc1034identifier) 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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/MenuViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuViewController.swift 3 | // AirbnbViewController-Sample 4 | // 5 | // Created by pixyzehn on 1/27/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MenuViewController: AirbnbViewController, AirbnbMenuDelegate, AirbnbMenuDataSource { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | self.view.backgroundColor = UIColor.whiteColor() 16 | } 17 | 18 | //MARK: AirbnbMenuDataSource 19 | 20 | override func numberOfSession() -> Int { 21 | return 10 22 | } 23 | 24 | override func numberOfRowsInSession(session: Int) -> Int { 25 | return 3 26 | } 27 | 28 | override func titleForRowAtIndexPath(indexPath: NSIndexPath) -> String { 29 | return "Row \(indexPath.row) in \(indexPath.section)" 30 | } 31 | 32 | override func titleForHeaderAtSession(session: Int) -> String { 33 | return "Session \(session)" 34 | } 35 | 36 | func viewControllerForIndexPath(indexPath: NSIndexPath) -> UIViewController { 37 | let viewController: ViewController = ViewController() 38 | 39 | let controller: UINavigationController = UINavigationController(rootViewController: viewController) 40 | 41 | switch indexPath.row { 42 | case 0: 43 | viewController.view.backgroundColor = UIColor(red:0.13, green:0.14, blue:0.15, alpha:1) 44 | case 1: 45 | viewController.view.backgroundColor = UIColor(red:0.95, green:0.95, blue:0.95, alpha:1) 46 | case 2: 47 | viewController.view.backgroundColor = UIColor(red:0.8, green:0, blue:0.48, alpha:1) 48 | default: 49 | break 50 | } 51 | return controller 52 | } 53 | 54 | //MARK: AirbnbMenuDelegate 55 | 56 | func didSelectRowAtIndex(indexPath: NSIndexPath) { 57 | print("didSelectRowAtIndex:\(indexPath.row)\n") 58 | } 59 | 60 | func shouldSelectRowAtIndex(indexPath: NSIndexPath) -> Bool { 61 | return true 62 | } 63 | 64 | func willShowAirViewController() { 65 | print("willShowAirViewController\n") 66 | } 67 | 68 | func willHideAirViewController() { 69 | print("willHideAirViewController\n") 70 | } 71 | 72 | func didHideAirViewController() { 73 | print("didHideAirViewController\n") 74 | } 75 | 76 | func heightForAirMenuRow() -> CGFloat { 77 | return 90.0 78 | } 79 | 80 | func indexPathDefaultValue() -> NSIndexPath? { 81 | return NSIndexPath(index: 2) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-Sample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AirbnbViewController-Sample 4 | // 5 | // Created by pixyzehn on 1/27/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | self.view.backgroundColor = UIColor.blackColor() 17 | 18 | var button: UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton 19 | button.frame = CGRectMake(0, 0, 50, 35) 20 | button.setTitle("Menu", forState: UIControlState.Normal) 21 | button.setTitleColor(UIColor(red:0.3, green:0.69, blue:0.75, alpha:1), forState: UIControlState.Normal) 22 | button.addTarget(self, action: "leftButtonTouch", forControlEvents: UIControlEvents.TouchUpInside) 23 | 24 | self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button) 25 | 26 | self.airSwipeHandler = {() -> Void in 27 | self.airViewController.showAirViewFromViewController(self.navigationController, complete: nil) 28 | return 29 | } 30 | } 31 | 32 | func leftButtonTouch() { 33 | self.airViewController.showAirViewFromViewController(self.navigationController, complete: nil) 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-SampleTests/AirbnbViewController_SampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirbnbViewController_SampleTests.swift 3 | // AirbnbViewController-SampleTests 4 | // 5 | // Created by pixyzehn on 1/27/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class AirbnbViewController_SampleTests: 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 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AirbnbViewController-Sample/AirbnbViewController-SampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | pixyzehn.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /AirbnbViewController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "AirbnbViewController" 3 | s.version = "1.0.3" 4 | s.summary = "Airbnb 4.7's three-dimensional slide menu. Unfortunately, this menu was obsoleted in Airbnb 5.0. " 5 | s.homepage = 'https://github.com/pixyzehn/AirbnbViewController' 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "pixyzehn" => "civokjots0109@gmail.com" } 8 | 9 | s.requires_arc = true 10 | s.ios.deployment_target = "8.0" 11 | s.source = { :git => "https://github.com/pixyzehn/AirbnbViewController.git", :tag => "#{s.version}" } 12 | s.source_files = "AirbnbViewController/*.{h,m,swift}" 13 | end 14 | -------------------------------------------------------------------------------- /AirbnbViewController/AirbnbHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // BlockWrapper.h 3 | // AirbnbViewController 4 | // 5 | // Created by pixyzehn on 1/26/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AirbnbHelper: NSObject 12 | 13 | typedef void (^airHandler)(); 14 | 15 | + (id) usingClosureWrapper:(airHandler)closure; 16 | + (airHandler) usingAnyObjectWrapper:(id)any; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /AirbnbViewController/AirbnbHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // BlockWrapper.m 3 | // AirbnbViewController 4 | // 5 | // Created by pixyzehn on 1/26/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | #import "AirbnbHelper.h" 10 | 11 | @interface AirbnbHelper() 12 | @end 13 | 14 | @implementation AirbnbHelper 15 | 16 | + (id) usingClosureWrapper:(airHandler)closure { 17 | return (id)closure; 18 | } 19 | 20 | + (airHandler) usingAnyObjectWrapper:(id)any { 21 | return (airHandler)any; 22 | } 23 | 24 | @end -------------------------------------------------------------------------------- /AirbnbViewController/AirbnbSessionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirbnbSessionView.swift 3 | // AirbnbViewController 4 | // 5 | // Created by pixyzehn on 1/1/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public class AirbnbSessionView: UIView { 13 | 14 | required public init(coder aDecoder: NSCoder) { 15 | super.init(coder: aDecoder) 16 | } 17 | 18 | private var _button: UIButton? 19 | public var button: UIButton? { 20 | get { 21 | if let btn = _button { 22 | return btn 23 | } else { 24 | _button = UIButton.buttonWithType(UIButtonType.Custom) as? UIButton 25 | _button?.frame = CGRectMake(0, 40, frame.size.width, kHeaderTitleHeight - 40.0) 26 | _button?.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left 27 | addSubview(_button!) 28 | return _button 29 | } 30 | } 31 | set { 32 | _button = newValue 33 | } 34 | } 35 | 36 | private var _containView: UIView? 37 | public var containView: UIView? { 38 | get { 39 | if let cv = _containView { 40 | return cv 41 | } else { 42 | _containView = UIView(frame: CGRectMake(0, kHeaderTitleHeight + 20, frame.size.width, frame.size.height - kHeaderTitleHeight)) 43 | addSubview(_containView!) 44 | return _containView 45 | } 46 | } 47 | set { 48 | _containView = newValue 49 | } 50 | } 51 | 52 | override public init(frame: CGRect) { 53 | super.init(frame: frame) 54 | } 55 | 56 | deinit { 57 | self.button?.removeFromSuperview() 58 | self.button = nil 59 | self.containView?.removeFromSuperview() 60 | self.containView = nil 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AirbnbViewController/AirbnbViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirbnbViewController.swift 3 | // AirbnbViewController 4 | // 5 | // Created by pixyzehn on 1/1/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | @objc public protocol AirbnbMenuDelegate: NSObjectProtocol { 13 | optional func shouldSelectRowAtIndex(indexPath: NSIndexPath) -> Bool 14 | optional func didSelectRowAtIndex(indexPath: NSIndexPath) 15 | optional func willShowAirViewController() 16 | optional func willHideAirViewController() 17 | optional func didHideAirViewController() 18 | optional func heightForAirMenuRow() -> CGFloat 19 | optional func indexPathDefaultValue() -> NSIndexPath? 20 | } 21 | 22 | @objc public protocol AirbnbMenuDataSource: NSObjectProtocol { 23 | func numberOfSession() -> Int 24 | func numberOfRowsInSession(sesion: Int) -> Int 25 | func titleForRowAtIndexPath(indexPath: NSIndexPath) -> String 26 | func titleForHeaderAtSession(session: Int) -> String 27 | optional func thumbnailImageAtIndexPath(indexPath: NSIndexPath) -> UIImage? 28 | optional func viewControllerForIndexPath(indexPath: NSIndexPath) -> UIViewController 29 | } 30 | 31 | public let kSessionWidth: CGFloat = 220 32 | public let kLeftViewTransX: CGFloat = -50 33 | public let kLeftViewRotate: CGFloat = -5 34 | public let kAirImageViewRotate: CGFloat = -25 35 | public let kRightViewTransX: CGFloat = 180 36 | public let kRightViewTransZ: CGFloat = -150 37 | public let kAirImageViewRotateMax: CGFloat = -42 38 | public let kDuration = 0.2 39 | public let kIndexPathOutMenu = NSIndexPath(forRow: 999, inSection: 0) 40 | public let kHeaderTitleHeight: CGFloat = 80 41 | 42 | //MARK: Convert unit 43 | 44 | private var AirDegreesToRadians = {(degrees: CGFloat) -> CGFloat in 45 | return degrees * CGFloat(M_PI) / 180.0 46 | } 47 | 48 | private var AirRadiansToDegrees = {(radians: CGFloat) -> CGFloat in 49 | return radians * 180 / CGFloat(M_PI) 50 | } 51 | 52 | public class AirbnbViewController: UIViewController, AirbnbMenuDelegate, AirbnbMenuDataSource, UIGestureRecognizerDelegate { 53 | 54 | public var titleNormalColor: UIColor? 55 | public var titleHighlightColor: UIColor? 56 | public var delegate: AirbnbMenuDelegate? 57 | public var dataSource: AirbnbMenuDataSource? 58 | public var fontViewController: UIViewController? 59 | public var currentIndexPath: NSIndexPath = NSIndexPath(forItem: 0, inSection: 0) 60 | public let complete = ({ () -> Void in }) 61 | 62 | private var _wrapperView: UIView? 63 | public var wrapperView: UIView? { 64 | get { 65 | if let wv = _wrapperView { 66 | return wv 67 | } else { 68 | let view: UIView = UIView(frame: CGRectMake(0, 0, self.view.width, self.view.height)) 69 | _wrapperView = view 70 | return view 71 | } 72 | } 73 | set { 74 | _wrapperView = newValue 75 | } 76 | } 77 | 78 | private var _contentView: UIView? 79 | public var contentView: UIView? { 80 | get { 81 | if let cv = _contentView { 82 | return cv 83 | } else { 84 | let view: UIView = UIView(frame: CGRectMake(0, 0, self.view.width, self.view.height)) 85 | _contentView = view 86 | return view 87 | } 88 | } 89 | set { 90 | _contentView = newValue 91 | } 92 | } 93 | 94 | private var _leftView: UIView? 95 | public var leftView: UIView? { 96 | get { 97 | if let lv = _leftView { 98 | return lv 99 | } else { 100 | let view: UIView = UIView(frame: CGRectMake(0, -(self.view.height - kHeaderTitleHeight), kSessionWidth, (self.view.height - kHeaderTitleHeight) * 3)) 101 | view.userInteractionEnabled = true 102 | _leftView = view 103 | return view 104 | } 105 | } 106 | set { 107 | _leftView = newValue 108 | } 109 | } 110 | 111 | private var _rightView: UIView? 112 | public var rightView: UIView? { 113 | get { 114 | if let rv = _rightView { 115 | return rv 116 | } else { 117 | let view: UIView = UIView(frame: CGRectMake(0, 0, self.view.width, self.view.height)) 118 | view.userInteractionEnabled = true 119 | _rightView = view 120 | return view 121 | } 122 | } 123 | set { 124 | _rightView = newValue 125 | } 126 | } 127 | 128 | private var _airImageView: UIImageView? 129 | public var airImageView: UIImageView? { 130 | get { 131 | if let aiv = _airImageView { 132 | return aiv 133 | } else { 134 | let imageView: UIImageView = UIImageView(frame: CGRectMake(0, 0, self.view.width, self.view.height)) 135 | imageView.userInteractionEnabled = true 136 | _airImageView = imageView 137 | return imageView 138 | } 139 | } 140 | set { 141 | _airImageView = newValue 142 | } 143 | } 144 | 145 | private var lastDeegreesRotateTransform: CGFloat? 146 | private var panGestureRecognizer: UIPanGestureRecognizer? 147 | 148 | public var session: Int? 149 | public var rowsOfSession: [Int]? 150 | public var sessionViews: Dictionary? 151 | public var currentIndexSession: Int = 0 152 | public var isAnimation: Bool? 153 | public var topSession: AirbnbSessionView? 154 | public var middleSession: AirbnbSessionView? 155 | public var bottomSession: AirbnbSessionView? 156 | public var lastIndexInSession: Dictionary = [0:0] 157 | public var thumbnailImages: [Dictionary]? 158 | public var viewControllers: [Dictionary]? 159 | public var heightAirMenuRow: CGFloat? 160 | 161 | override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 162 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 163 | } 164 | 165 | convenience public init(viewController: UIViewController, atIndexPath:NSIndexPath) { 166 | self.init() 167 | let rect = UIScreen.mainScreen().applicationFrame 168 | self.view.frame = CGRectMake(0, 0, rect.width, rect.height) 169 | self.bringViewControllerToTop(viewController, indexPath: atIndexPath) 170 | } 171 | 172 | required public init(coder aDecoder: NSCoder) { 173 | super.init(coder: aDecoder) 174 | } 175 | 176 | override public func viewDidLoad() { 177 | super.viewDidLoad() 178 | 179 | sessionViews = Dictionary() 180 | 181 | currentIndexPath = NSIndexPath(forItem: 0, inSection: 0) 182 | 183 | self.delegate = self 184 | self.dataSource = self 185 | 186 | self.view.addSubview(wrapperView!) 187 | self.wrapperView?.addSubview(contentView!) 188 | 189 | self.contentView?.addSubview(leftView!) 190 | self.contentView?.addSubview(rightView!) 191 | 192 | self.rightView?.addSubview(airImageView!) 193 | 194 | self.titleNormalColor = UIColor(red: 0.45, green: 0.45, blue: 0.45, alpha: 1.0) 195 | self.titleHighlightColor = UIColor.blackColor() 196 | 197 | let swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipeOnAirImageView:") 198 | swipe.direction = UISwipeGestureRecognizerDirection.Left 199 | self.airImageView?.addGestureRecognizer(swipe) 200 | 201 | let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleTapOnAirImageView:") 202 | self.airImageView?.addGestureRecognizer(tap) 203 | 204 | self.panGestureRecognizer = UIPanGestureRecognizer(target: self, action: "handleRevealGesture:") 205 | self.panGestureRecognizer?.delegate = self 206 | self.leftView?.addGestureRecognizer(panGestureRecognizer!) 207 | 208 | self.setupAnimation() 209 | 210 | self.leftView?.alpha = 0 211 | self.rightView?.alpha = 0 212 | 213 | self.heightAirMenuRow = 44 214 | } 215 | 216 | override public func viewWillAppear(animated: Bool) { 217 | super.viewWillAppear(animated) 218 | self.reloadData() 219 | } 220 | 221 | public func bringViewControllerToTop(controller: UIViewController?, indexPath: NSIndexPath) { 222 | 223 | if (controller == nil) { 224 | return 225 | } 226 | 227 | if let fvController = self.fontViewController { 228 | fvController.removeFromParentViewController() 229 | fvController.view.removeFromSuperview() 230 | } 231 | 232 | self.fontViewController = controller 233 | self.currentIndexPath = indexPath 234 | 235 | if indexPath.row != kIndexPathOutMenu.row { 236 | self.lastIndexInSession[indexPath.section] = indexPath.row 237 | self.saveViewControler(controller, atIndexPath: indexPath) 238 | } 239 | 240 | self.addChildViewController(self.fontViewController!) 241 | let controllerView: UIView = self.fontViewController!.view 242 | controllerView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight 243 | controllerView.frame = self.view.bounds 244 | self.view.addSubview(controllerView) 245 | 246 | self.fontViewController?.didMoveToParentViewController(self) 247 | } 248 | 249 | //MARK: Gesture delegate 250 | 251 | public func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { 252 | if isAnimation == true { 253 | return false 254 | } 255 | return true 256 | } 257 | 258 | //MARK: AirImageView gesture 259 | 260 | public func handleSwipeOnAirImageView(swipe: UISwipeGestureRecognizer) { 261 | self.hideAirViewOnComplete({() -> Void in 262 | self.bringViewControllerToTop(self.fontViewController, indexPath: self.currentIndexPath) 263 | }) 264 | } 265 | 266 | public func handleTapOnAirImageView(swipe: UITapGestureRecognizer) { 267 | self.hideAirViewOnComplete({() -> Void in 268 | self.bringViewControllerToTop(self.fontViewController, indexPath: self.currentIndexPath) 269 | }) 270 | } 271 | 272 | //MARK: Gesture Based Reveal 273 | 274 | public func handleRevealGesture(recognizer: UIPanGestureRecognizer) { 275 | 276 | if self.sessionViews?.count == 0 || self.sessionViews?.count == 1 { 277 | return 278 | } 279 | 280 | switch recognizer.state { 281 | case UIGestureRecognizerState.Began: 282 | handleRevealGestureStateBeganWithRecognizer(recognizer) 283 | case UIGestureRecognizerState.Changed: 284 | handleRevealGestureStateChangedWithRecognizer(recognizer) 285 | case UIGestureRecognizerState.Ended: 286 | handleRevealGestureStateEndedWithRecognizer(recognizer) 287 | case UIGestureRecognizerState.Cancelled: 288 | handleRevealGestureStateCancelledWithRecognizer(recognizer) 289 | default: 290 | break 291 | } 292 | } 293 | 294 | public func handleRevealGestureStateBeganWithRecognizer(recognizer: UIPanGestureRecognizer) { 295 | } 296 | 297 | public func handleRevealGestureStateChangedWithRecognizer(recognizer: UIPanGestureRecognizer) { 298 | 299 | let translation: CGFloat = recognizer.translationInView(self.leftView!).y 300 | 301 | self.leftView!.top = -(self.view.height - kHeaderTitleHeight) + translation 302 | 303 | let firstTop: Int = -Int(self.view.height - kHeaderTitleHeight) 304 | let afterTop: Int = Int(self.leftView!.top) 305 | 306 | let sessionViewHeight: Int = Int(self.view.height - kHeaderTitleHeight) 307 | var distanceScroll: Int = 0 308 | 309 | if afterTop - firstTop > 0 { 310 | let topMiddleSessionView: Int = Int(self.leftView!.top) + sessionViewHeight + 40 311 | 312 | if topMiddleSessionView < Int(self.view.height / 2) { 313 | distanceScroll = Int(self.view.height / 2) - topMiddleSessionView 314 | } else { 315 | distanceScroll = topMiddleSessionView - Int(self.view.height / 2) + 40 316 | } 317 | } else { 318 | let bottomMiddleSessionView: Int = Int(self.leftView!.top) + sessionViewHeight * 2 319 | 320 | if bottomMiddleSessionView > Int(self.view.height / 2) { 321 | distanceScroll = bottomMiddleSessionView - Int(self.view.height / 2) 322 | } else { 323 | distanceScroll = Int(self.view.height / 2) - bottomMiddleSessionView 324 | } 325 | } 326 | 327 | distanceScroll = abs(Int(self.view.height / 2) - distanceScroll) 328 | 329 | let rotateDegress: CGFloat = CGFloat(distanceScroll * Int(abs(kAirImageViewRotateMax - kAirImageViewRotate))) / (self.view.height / 2) 330 | self.lastDeegreesRotateTransform = rotateDegress 331 | 332 | var airImageRotate: CATransform3D = CATransform3DIdentity 333 | airImageRotate = CATransform3DRotate(airImageRotate, AirDegreesToRadians(kAirImageViewRotate - rotateDegress), 0, 1, 0) 334 | self.airImageView?.layer.transform = airImageRotate 335 | } 336 | 337 | //MARK: Judge whether to transit or not 338 | 339 | public func handleRevealGestureStateEndedWithRecognizer(recognizer: UIPanGestureRecognizer) { 340 | 341 | if sessionViews?.count == 0 { 342 | return 343 | } 344 | 345 | let firstTop: Int = -Int(self.view.height - kHeaderTitleHeight) 346 | let afterTop: Int = Int(self.leftView!.top) 347 | 348 | let velocity: CGPoint = recognizer.velocityInView(recognizer.view) 349 | 350 | if afterTop - firstTop > 0 { 351 | if afterTop - firstTop > Int(self.view.height / 2) - 40 || abs(velocity.y) > 100 { 352 | self.prevSession() 353 | } else { 354 | self.slideCurrentSession() 355 | } 356 | } else { 357 | if firstTop - afterTop > Int(self.view.height / 2) - 40 || abs(velocity.y) > 100 { 358 | self.nextSession() 359 | } else { 360 | self.slideCurrentSession() 361 | } 362 | } 363 | } 364 | 365 | public func handleRevealGestureStateCancelledWithRecognizer(recognizer: UIPanGestureRecognizer) { 366 | } 367 | 368 | public func nextSession() { 369 | self.currentIndexSession++ 370 | if self.currentIndexSession >= self.sessionViews?.count { 371 | self.currentIndexSession = 0 372 | } 373 | 374 | if let index = self.lastIndexInSession[self.currentIndexSession] { 375 | let lastIndexInThisSession: NSIndexPath = NSIndexPath(forRow:index, inSection: self.currentIndexSession) 376 | let nextThumbnail: UIImage? = self.getThumbnailImageAtIndexPath(lastIndexInThisSession) 377 | if let image = nextThumbnail { 378 | self.airImageView?.image = image 379 | } 380 | } 381 | 382 | UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 383 | self?.leftView?.top = -(self!.leftView!.height / 3.0) * 2.0 384 | return 385 | }, completion: {(finished: Bool) -> Void in 386 | self.layoutContaintView() 387 | }) 388 | 389 | self.rotateAirImage() 390 | } 391 | 392 | public func prevSession() { 393 | self.currentIndexSession-- 394 | if self.currentIndexSession < 0 { 395 | self.currentIndexSession = self.sessionViews!.count - 1 396 | } 397 | 398 | if let index = self.lastIndexInSession[self.currentIndexSession] { 399 | let lastIndexInThisSession: NSIndexPath = NSIndexPath(forRow: index, inSection: self.currentIndexSession) 400 | let prevThumbnail: UIImage? = self.getThumbnailImageAtIndexPath(lastIndexInThisSession) 401 | if let prev = prevThumbnail { 402 | self.airImageView?.image = prev 403 | } 404 | } 405 | 406 | UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 407 | self?.leftView?.top = 0 408 | return 409 | }, completion: {(finished: Bool) -> Void in 410 | self.layoutContaintView() 411 | }) 412 | 413 | self.rotateAirImage() 414 | } 415 | 416 | public func slideCurrentSession() { 417 | UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 418 | self!.leftView!.top = -self!.leftView!.height / 3.0 419 | return 420 | }, completion: {(finished: Bool) -> Void in 421 | }) 422 | 423 | self.rotateAirImage() 424 | } 425 | 426 | public func rotateAirImage() { 427 | if self.lastDeegreesRotateTransform > 0 { 428 | UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 429 | var airImageRotate: CATransform3D = self!.airImageView!.layer.transform 430 | airImageRotate = CATransform3DRotate(airImageRotate, CGFloat(AirDegreesToRadians(self!.lastDeegreesRotateTransform!)),0,1,0) 431 | self?.airImageView?.layer.transform = airImageRotate 432 | }, completion: {(finished: Bool) -> Void in 433 | self.lastDeegreesRotateTransform = 0 434 | }) 435 | } else { 436 | let rotateDegress: CGFloat = abs(kAirImageViewRotateMax - kAirImageViewRotate) as CGFloat 437 | 438 | UIView.animateWithDuration(0.15, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 439 | var airImageRotate: CATransform3D = self!.airImageView!.layer.transform 440 | airImageRotate = CATransform3DRotate(airImageRotate, AirDegreesToRadians(-rotateDegress), 0, 1, 0) 441 | self?.airImageView?.layer.transform = airImageRotate 442 | 443 | return 444 | }, completion: {(finished: Bool) -> Void in 445 | UIView.animateWithDuration(0.15, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 446 | var airImageRotate: CATransform3D = self!.airImageView!.layer.transform 447 | airImageRotate = CATransform3DRotate(airImageRotate, AirDegreesToRadians(rotateDegress), 0, 1, 0) 448 | self?.airImageView?.layer.transform = airImageRotate 449 | return 450 | }, completion: {(finished: Bool) -> Void in 451 | self.lastDeegreesRotateTransform = 0 452 | }) 453 | }) 454 | } 455 | } 456 | 457 | public func reloadData() { 458 | if self.dataSource == nil { 459 | return 460 | } 461 | 462 | self.session = self.dataSource?.numberOfSession() 463 | 464 | if let heightForAirMenuRow = self.delegate?.heightForAirMenuRow?() { 465 | self.heightAirMenuRow = heightForAirMenuRow 466 | } 467 | 468 | var tempThumbnails: [Dictionary] = [Dictionary()] 469 | var tempViewControllers: [Dictionary] = [Dictionary()] 470 | 471 | for var i:Int = 0; i < self.session; i++ { 472 | tempThumbnails.append(Dictionary()) 473 | tempViewControllers.append(Dictionary()) 474 | } 475 | self.thumbnailImages = tempThumbnails 476 | self.viewControllers = tempViewControllers 477 | 478 | var temp: Array = [Int]() 479 | for var i:Int = 0; i < self.session; i++ { 480 | temp.append(self.dataSource!.numberOfRowsInSession(i)) 481 | 482 | } 483 | self.rowsOfSession = temp 484 | 485 | let sessionHeight: CGFloat = CGFloat(self.view.frame.size.height - kHeaderTitleHeight) 486 | 487 | for var i:Int = 0; i < self.session; i++ { 488 | var sessionView: AirbnbSessionView? = self.sessionViews![i] 489 | if sessionView == nil { 490 | sessionView = AirbnbSessionView(frame:CGRectMake(30, 0, kSessionWidth, sessionHeight)) 491 | sessionView?.button?.setTitleColor(UIColor(red: 0.45, green: 0.45, blue: 0.45, alpha: 1.0), forState: UIControlState.Normal) 492 | sessionView?.button?.titleLabel?.font = UIFont(name: "HelveticaNeue-Light", size: 20) 493 | sessionView?.button?.tag = i 494 | sessionView?.button?.addTarget(self, action: "sessionButtonTouch:", forControlEvents: UIControlEvents.TouchUpInside) 495 | self.sessionViews![i] = sessionView! 496 | } 497 | let sesionTitle: String? = self.dataSource?.titleForHeaderAtSession(i) 498 | sessionView?.button?.setTitle(sesionTitle, forState: UIControlState.Normal) 499 | } 500 | 501 | for var i:Int = 0; i < self.session; i++ { 502 | var sessionView: AirbnbSessionView? = sessionViews![i]! 503 | 504 | for view in sessionView!.containView!.subviews { 505 | view.removeFromSuperview() 506 | } 507 | 508 | var firstTop: Int = (Int(sessionView!.containView!.frame.size.height) - (self.rowsOfSession![i] * Int(self.heightAirMenuRow!))) / 2 509 | 510 | if firstTop < 0 { 511 | firstTop = 0 512 | } 513 | 514 | for var j: Int = 0; j < self.rowsOfSession![i]; j++ { 515 | let title: String = self.dataSource!.titleForRowAtIndexPath(NSIndexPath(forRow: j, inSection: i)) 516 | var button: UIButton? = UIButton.buttonWithType(UIButtonType.Custom) as? UIButton 517 | button!.setTitle(title, forState: UIControlState.Normal) 518 | button!.addTarget(self, action: "rowDidTouch:", forControlEvents: UIControlEvents.TouchUpInside) 519 | button!.setTitleColor(self.titleNormalColor, forState: UIControlState.Normal) 520 | button!.setTitleColor(self.titleHighlightColor!, forState: UIControlState.Highlighted) 521 | button!.setTitleColor(self.titleHighlightColor!, forState: UIControlState.Selected) 522 | button!.titleLabel!.font = UIFont(name: "HelveticaNeue-Light", size: 16) 523 | button!.contentHorizontalAlignment = UIControlContentHorizontalAlignment.Left 524 | let y: CGFloat = CGFloat(firstTop) + CGFloat(self.heightAirMenuRow!) * CGFloat(j) 525 | button!.frame = CGRectMake(0, y, 200, CGFloat(self.heightAirMenuRow!)) 526 | button!.tag = j 527 | sessionView!.containView!.tag = i 528 | sessionView?.containView?.addSubview(button!) 529 | } 530 | } 531 | self.layoutContaintView() 532 | } 533 | 534 | public func layoutContaintView() { 535 | if sessionViews!.count == 1 { 536 | middleSession = sessionViews![0] 537 | self.topSession = nil 538 | self.bottomSession = nil 539 | 540 | middleSession?.top = middleSession!.height 541 | self.leftView?.addSubview(middleSession!) 542 | 543 | self.leftView?.top = -(self.leftView!.height) / 3 544 | 545 | self.updateButtonColor() 546 | return 547 | } 548 | 549 | if let ts = self.topSession?.superview { 550 | self.topSession?.removeFromSuperview() 551 | self.topSession = nil 552 | } 553 | 554 | if let ms = self.middleSession?.superview { 555 | self.middleSession?.removeFromSuperview() 556 | self.middleSession = nil 557 | } 558 | 559 | if let bs = self.bottomSession?.superview { 560 | self.bottomSession?.removeFromSuperview() 561 | self.bottomSession = nil 562 | } 563 | 564 | if sessionViews!.count == 1 { 565 | // count 1 566 | self.middleSession = self.sessionViews![0] 567 | self.topSession = self.duplicate(self.middleSession!) as? AirbnbSessionView 568 | self.bottomSession = self.duplicate(self.middleSession!) as? AirbnbSessionView 569 | } else if sessionViews!.count == 2 { 570 | // count 2 571 | self.middleSession = self.sessionViews![self.currentIndexSession] 572 | if currentIndexSession == 0 { 573 | var hoge = self.sessionViews 574 | self.topSession = self.sessionViews![1]! 575 | self.bottomSession = self.duplicate(self.sessionViews![1]!) as? AirbnbSessionView 576 | } else { 577 | self.topSession = self.sessionViews![0]! 578 | self.bottomSession = self.duplicate(self.sessionViews![0]!) as? AirbnbSessionView 579 | } 580 | } else { 581 | //count more than 3 582 | self.middleSession = sessionViews![self.currentIndexSession] 583 | if self.currentIndexSession == 0 { 584 | self.topSession = self.sessionViews![self.sessionViews!.count - 1] 585 | } else { 586 | self.topSession = self.sessionViews![self.currentIndexSession - 1] 587 | } 588 | if self.currentIndexSession + 1 >= self.sessionViews?.count { 589 | self.bottomSession = sessionViews![0] 590 | } else { 591 | self.bottomSession = self.sessionViews![self.currentIndexSession + 1] 592 | } 593 | } 594 | 595 | self.topSession!.top = 0 596 | self.middleSession!.top = self.topSession!.bottom 597 | self.bottomSession!.top = self.middleSession!.bottom 598 | 599 | self.leftView?.addSubview(self.topSession!) 600 | self.leftView?.addSubview(self.middleSession!) 601 | self.leftView?.addSubview(self.bottomSession!) 602 | 603 | self.leftView!.top = -(self.leftView!.height)/3 604 | 605 | self.updateButtonColor() 606 | } 607 | 608 | public func updateButtonColor() { 609 | for var i: Int = 0; i < self.sessionViews?.count; i++ { 610 | var sessionView: AirbnbSessionView? = self.sessionViews?[i] 611 | var indexHighlight: Int? = self.lastIndexInSession[i] 612 | 613 | for object in sessionView!.containView!.allSubviews { 614 | if object is UIButton { 615 | var button: UIButton = object as! UIButton 616 | button.highlighted = button.tag == indexHighlight ? true : false 617 | } 618 | } 619 | } 620 | } 621 | 622 | //MARK: PHAirMenuDelegate 623 | 624 | public func numberOfSession() -> Int { 625 | return 0 626 | } 627 | 628 | public func numberOfRowsInSession(sesion: Int) -> Int { 629 | return 0 630 | } 631 | 632 | public func titleForRowAtIndexPath(indexPath: NSIndexPath) -> String { 633 | return "" 634 | } 635 | 636 | public func titleForHeaderAtSession(session: Int) -> String { 637 | return "" 638 | } 639 | 640 | //MARK: Button action 641 | 642 | public func sessionButtonTouch(buttton: UIButton) { 643 | if buttton.tag == self.currentIndexSession { 644 | return 645 | } else { 646 | self.nextSession() 647 | } 648 | } 649 | 650 | public func rowDidTouch(button: UIButton) { 651 | 652 | self.lastIndexInSession[self.currentIndexSession] = button.superview!.tag 653 | 654 | self.currentIndexPath = NSIndexPath(forRow: button.tag, inSection: button.superview!.tag) 655 | 656 | if self.delegate != nil && self.delegate?.respondsToSelector("didSelectRowAtIndex:") != nil { 657 | self.delegate?.didSelectRowAtIndex!(self.currentIndexPath) 658 | } 659 | 660 | if let nextThumbnail = self.getThumbnailImageAtIndexPath(self.currentIndexPath) { 661 | self.airImageView!.image = nextThumbnail 662 | } 663 | 664 | self.hideAirViewOnComplete({() -> Void in 665 | let controller: UIViewController? = self.getViewControllerAtIndexPath(self.currentIndexPath) 666 | if controller != nil { 667 | self.bringViewControllerToTop(controller, indexPath: self.currentIndexPath) 668 | } else { 669 | let controller: UIViewController! = self.dataSource?.viewControllerForIndexPath!(self.currentIndexPath) 670 | self.bringViewControllerToTop(controller, indexPath: self.currentIndexPath) 671 | } 672 | 673 | }) 674 | } 675 | 676 | //MARK: Show/Hide air view controller 677 | 678 | public func showAirViewFromViewController(controller: UIViewController?, complete: (() -> Void)? ) { 679 | self.updateButtonColor() 680 | 681 | if let willShow: () = self.delegate?.willShowAirViewController?() { 682 | willShow 683 | } 684 | 685 | self.airImageView?.image = self.imageWithView(controller!.view) 686 | self.saveThumbnailImage(self.airImageView?.image, atIndexPath: self.currentIndexPath) 687 | self.saveViewControler(controller, atIndexPath: self.currentIndexPath) 688 | 689 | self.view.bringSubviewToFront(self.wrapperView!) 690 | self.contentView?.bringSubviewToFront(self.leftView!) 691 | self.contentView?.bringSubviewToFront(self.rightView!) 692 | 693 | if controller != nil { 694 | controller?.removeFromParentViewController() 695 | controller?.view.removeFromSuperview() 696 | } 697 | 698 | self.airImageView?.layer.transform = CATransform3DIdentity 699 | self.contentView?.layer.transform = CATransform3DIdentity 700 | 701 | var leftTransform: CATransform3D = CATransform3DIdentity 702 | leftTransform = CATransform3DTranslate(leftTransform, kLeftViewTransX, 0, 0) 703 | leftTransform = CATransform3DRotate(leftTransform, AirDegreesToRadians(kLeftViewRotate), 0, 1, 0) 704 | self.leftView?.layer.transform = leftTransform 705 | 706 | self.rightView?.alpha = 1 707 | self.leftView?.alpha = 0 708 | 709 | UIView.animateWithDuration(kDuration, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 710 | self?.leftView?.alpha = 1 711 | 712 | var airImageRotate: CATransform3D? = self?.airImageView?.layer.transform 713 | airImageRotate = CATransform3DRotate(airImageRotate!, AirDegreesToRadians(kAirImageViewRotate), 0, 1, 0) 714 | self?.airImageView?.layer.transform = airImageRotate! 715 | 716 | var rightTransform: CATransform3D? = self?.rightView?.layer.transform 717 | rightTransform = CATransform3DTranslate(rightTransform!, kRightViewTransX, 0, kRightViewTransZ) 718 | self?.rightView?.layer.transform = rightTransform! 719 | 720 | var leftTransform: CATransform3D? = self?.leftView?.layer.transform 721 | leftTransform = CATransform3DRotate(leftTransform!, AirDegreesToRadians(-kLeftViewRotate), 0, 1, 0) 722 | leftTransform = CATransform3DTranslate(leftTransform!, -kLeftViewTransX , 0, 0) 723 | self?.leftView?.layer.transform = leftTransform! 724 | 725 | return 726 | }, completion: {(finished: Bool) -> Void in 727 | if let com = complete { 728 | com() 729 | } 730 | }) 731 | 732 | self.airImageView?.tag = 1 733 | } 734 | 735 | public func switchToViewController(controller: UIViewController, atIndexPath: NSIndexPath) { 736 | self.bringViewControllerToTop(controller, indexPath: atIndexPath) 737 | } 738 | 739 | public func switchToViewController(controller: UIViewController) { 740 | self.bringViewControllerToTop(controller, indexPath: kIndexPathOutMenu) 741 | } 742 | 743 | public func hideAirViewOnComplete(complete: (() -> Void)?) { 744 | if let willHide: () = self.delegate?.willHideAirViewController?() { 745 | willHide 746 | } 747 | 748 | UIView.animateWithDuration(kDuration, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {[weak self]() -> Void in 749 | self?.leftView?.alpha = 0 750 | 751 | var airImageRotate: CATransform3D? = self?.airImageView?.layer.transform 752 | airImageRotate = CATransform3DRotate(airImageRotate!, AirDegreesToRadians(-kAirImageViewRotate), 0, 1, 0) 753 | self?.airImageView?.layer.transform = airImageRotate! 754 | 755 | var rightTransform: CATransform3D? = self?.rightView?.layer.transform 756 | rightTransform = CATransform3DTranslate(rightTransform!, -kRightViewTransX, 0, -kRightViewTransZ) 757 | self?.rightView?.layer.transform = rightTransform! 758 | 759 | var leftTransform: CATransform3D? = self?.leftView?.layer.transform 760 | leftTransform = CATransform3DRotate(leftTransform!, AirDegreesToRadians(kLeftViewRotate), 0, 1, 0) 761 | leftTransform = CATransform3DTranslate(leftTransform!, kLeftViewTransX, 0, 0) 762 | self?.leftView?.layer.transform = leftTransform! 763 | 764 | }, completion: {(finished: Bool) -> Void in 765 | self.leftView?.alpha = 0 766 | self.rightView?.alpha = 0 767 | 768 | self.leftView?.layer.transform = CATransform3DIdentity 769 | 770 | if let didHide: () = self.delegate?.didHideAirViewController?() { 771 | didHide 772 | } 773 | if let com = complete { 774 | com() 775 | } 776 | }) 777 | 778 | self.airImageView?.tag = 0 779 | } 780 | 781 | //MARK: Animation 782 | 783 | public func setupAnimation() { 784 | var rotationAndPerspectiveTransform: CATransform3D = CATransform3DIdentity 785 | rotationAndPerspectiveTransform.m34 = 1.0 / -600 786 | 787 | self.rightView?.layer.sublayerTransform = rotationAndPerspectiveTransform 788 | 789 | let anchorPoint: CGPoint = CGPointMake(1, 0.5) 790 | let newX: CGFloat = self.airImageView!.width * anchorPoint.x 791 | let newY: CGFloat = self.airImageView!.height * anchorPoint.y 792 | self.airImageView!.layer.position = CGPointMake(newX, newY) 793 | self.airImageView!.layer.anchorPoint = anchorPoint 794 | 795 | self.contentView?.layer.sublayerTransform = rotationAndPerspectiveTransform 796 | let anchorPoint2: CGPoint = CGPointMake(1, 0.5) 797 | let newX2: CGFloat = self.rightView!.width * anchorPoint2.x 798 | let newY2: CGFloat = self.rightView!.height * anchorPoint2.y 799 | self.rightView!.layer.position = CGPointMake(newX2, newY2) 800 | self.rightView!.layer.anchorPoint = anchorPoint2 801 | 802 | let leftAnchorPoint: CGPoint = CGPointMake(-3, 0.5) 803 | let newLeftX: CGFloat = self.leftView!.width * leftAnchorPoint.x 804 | let newLeftY: CGFloat = self.leftView!.height * leftAnchorPoint.y 805 | self.leftView!.layer.position = CGPointMake(newLeftX, newLeftY) 806 | self.leftView!.layer.anchorPoint = leftAnchorPoint 807 | 808 | let anchorPoint3: CGPoint = CGPointMake(1, 0.5) 809 | let newX3: CGFloat = self.contentView!.width * anchorPoint3.x 810 | let newY3: CGFloat = self.contentView!.height * anchorPoint3.y 811 | self.contentView!.layer.position = CGPointMake(newX3, newY3) 812 | self.contentView!.layer.anchorPoint = anchorPoint3 813 | } 814 | 815 | //MARK: Helper 816 | 817 | public func getThumbnailImageAtIndexPath(indexPath: NSIndexPath) -> UIImage? { 818 | let thumbnailDic: Dictionary = self.thumbnailImages![indexPath.section] 819 | if let tDic = thumbnailDic[indexPath.row] { 820 | return tDic 821 | } else { 822 | if let th = self.dataSource?.thumbnailImageAtIndexPath?(indexPath) { 823 | return th 824 | } else { 825 | return nil 826 | } 827 | } 828 | } 829 | 830 | public func saveThumbnailImage(image: UIImage?, atIndexPath indexPath: NSIndexPath) { 831 | if image == nil { 832 | return 833 | } 834 | 835 | var thumbnailDic: Dictionary = self.thumbnailImages![indexPath.section] 836 | thumbnailDic[indexPath.row] = image! 837 | } 838 | 839 | public func getViewControllerAtIndexPath(indexPath: NSIndexPath) -> UIViewController? { 840 | let viewControllerDic: Dictionary = self.viewControllers![indexPath.section] 841 | if let vDic = viewControllerDic[indexPath.row] { 842 | return vDic 843 | } else { 844 | return self.dataSource?.viewControllerForIndexPath!(indexPath) 845 | } 846 | } 847 | 848 | public func saveViewControler(controller: UIViewController?, atIndexPath indexPath: NSIndexPath) { 849 | if controller == nil { 850 | return 851 | } 852 | 853 | var viewControllerDic: Dictionary? = self.viewControllers?[indexPath.section] 854 | if viewControllerDic != nil { 855 | viewControllerDic![indexPath.row] = controller 856 | } 857 | } 858 | 859 | public func imageWithView(view: UIView) -> UIImage? { 860 | UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0.0) 861 | view.layer.renderInContext(UIGraphicsGetCurrentContext()) 862 | let img: UIImage = UIGraphicsGetImageFromCurrentImageContext() 863 | UIGraphicsEndImageContext() 864 | return img 865 | } 866 | 867 | public func duplicate(view: UIView) -> UIView? { 868 | let tempArchive: NSData = NSKeyedArchiver.archivedDataWithRootObject(view) 869 | return NSKeyedUnarchiver.unarchiveObjectWithData(tempArchive) as? AirbnbSessionView 870 | } 871 | 872 | deinit { 873 | self.airImageView?.removeFromSuperview() 874 | self.airImageView = nil 875 | self.rightView?.removeFromSuperview() 876 | self.rightView = nil 877 | self.leftView?.removeFromSuperview() 878 | self.leftView = nil 879 | self.wrapperView?.removeFromSuperview() 880 | self.wrapperView = nil 881 | self.rowsOfSession = nil 882 | } 883 | } 884 | 885 | public var SwipeTagHandle = "SWIPE_HANDER" 886 | public var SwipeObject = "SWIPE_OBJECT" 887 | 888 | public extension UIViewController { 889 | 890 | public var airSwipeGestureRecognizer: UISwipeGestureRecognizer? { 891 | get { 892 | var swipe: UISwipeGestureRecognizer? = objc_getAssociatedObject(self, &SwipeObject) as? UISwipeGestureRecognizer 893 | if let sw = swipe { 894 | return sw 895 | } else { 896 | swipe = UISwipeGestureRecognizer(target: self, action: "swipeHandler") 897 | swipe?.direction = UISwipeGestureRecognizerDirection.Right 898 | objc_setAssociatedObject(self, &SwipeObject, swipe, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) 899 | return swipe 900 | } 901 | 902 | } 903 | } 904 | 905 | public var airSwipeHandler: airHandler? { 906 | get { 907 | // AnyObject -> id -> airHandler 908 | return AirbnbHelper.usingAnyObjectWrapper(objc_getAssociatedObject(self, &SwipeTagHandle)) 909 | } 910 | set { 911 | if var obj: airHandler = newValue { 912 | if let view = self.airSwipeGestureRecognizer?.view { 913 | view.removeGestureRecognizer(self.airSwipeGestureRecognizer!) 914 | } 915 | 916 | if let nv = self.navigationController { 917 | nv.view.addGestureRecognizer(self.airSwipeGestureRecognizer!) 918 | } else { 919 | self.view.addGestureRecognizer(self.airSwipeGestureRecognizer!) 920 | } 921 | // airHandler -> id -> AnyObject 922 | objc_setAssociatedObject(self, &SwipeTagHandle, AirbnbHelper.usingClosureWrapper(obj), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) 923 | } else { 924 | if self.airSwipeGestureRecognizer?.view != nil { 925 | self.airSwipeGestureRecognizer?.view?.removeGestureRecognizer(self.airSwipeGestureRecognizer!) 926 | } 927 | if let ph = self.airSwipeGestureRecognizer?.view { 928 | ph.removeGestureRecognizer(self.airSwipeGestureRecognizer!) 929 | } 930 | } 931 | } 932 | } 933 | 934 | public var airViewController: AirbnbViewController { 935 | get { 936 | var parent: UIViewController = self 937 | var parent2 = parent.parentViewController! 938 | var parent3 = parent2.parentViewController! 939 | print(parent) 940 | return parent3 as! AirbnbViewController 941 | } 942 | } 943 | 944 | public func swipeHandler() { 945 | if let handler: airHandler = self.airSwipeHandler { 946 | handler() 947 | } 948 | } 949 | } 950 | 951 | //MARK: EXtension UIView 952 | 953 | public extension UIView { 954 | 955 | public var left: CGFloat { 956 | get { 957 | return self.frame.origin.x 958 | } 959 | set { 960 | var frame: CGRect = self.frame 961 | frame.origin.x = newValue 962 | self.frame = frame 963 | } 964 | } 965 | 966 | public var top: CGFloat { 967 | get { 968 | return self.frame.origin.y 969 | } 970 | set { 971 | var frame: CGRect = self.frame 972 | frame.origin.y = newValue 973 | self.frame = frame 974 | } 975 | } 976 | 977 | public var right: CGFloat { 978 | get { 979 | return self.frame.origin.x + self.frame.size.width 980 | } 981 | set { 982 | var frame: CGRect = self.frame 983 | frame.origin.x = newValue - frame.size.width 984 | self.frame = frame 985 | } 986 | } 987 | 988 | public var bottom: CGFloat { 989 | get { 990 | return self.frame.origin.y + self.frame.size.height 991 | } 992 | set { 993 | var frame: CGRect = self.frame 994 | frame.origin.y = newValue - frame.size.height 995 | self.frame = frame 996 | } 997 | } 998 | 999 | public var centerX: CGFloat { 1000 | get { 1001 | return self.center.x 1002 | } 1003 | set { 1004 | self.center = CGPointMake(newValue, self.center.y) 1005 | } 1006 | } 1007 | 1008 | public var centerY: CGFloat { 1009 | get { 1010 | return self.center.y 1011 | } 1012 | set { 1013 | self.center = CGPointMake(self.center.x, newValue) 1014 | } 1015 | } 1016 | 1017 | public var width: CGFloat { 1018 | get { 1019 | return self.frame.size.width 1020 | } 1021 | set { 1022 | var frame: CGRect = self.frame 1023 | frame.size.width = newValue 1024 | self.frame = frame 1025 | } 1026 | } 1027 | 1028 | public var height: CGFloat { 1029 | get { 1030 | return self.frame.size.height 1031 | } 1032 | set { 1033 | var frame: CGRect = self.frame 1034 | frame.size.height = newValue 1035 | self.frame = frame 1036 | } 1037 | } 1038 | 1039 | public var ttScreenX: CGFloat { 1040 | get { 1041 | var x: CGFloat = 0 1042 | var view: UIView? = self 1043 | for view; view == nil; view?.superview { 1044 | x += view!.left 1045 | } 1046 | return x 1047 | } 1048 | } 1049 | 1050 | public var ttScreenY: CGFloat { 1051 | get { 1052 | var y: CGFloat = 0 1053 | var view: UIView? = self 1054 | for (view; view == nil; view?.superview) { 1055 | y += view!.top 1056 | } 1057 | return y 1058 | } 1059 | } 1060 | 1061 | public var screenViewX: CGFloat { 1062 | get { 1063 | var x: CGFloat = 0 1064 | var view: UIView? = self 1065 | for (view; view == nil; view?.superview) { 1066 | x += view!.left 1067 | if view!.isKindOfClass(UIScrollView) { 1068 | var scrollView: UIScrollView = view as! UIScrollView 1069 | x -= scrollView.contentOffset.x 1070 | } 1071 | } 1072 | return x 1073 | } 1074 | } 1075 | 1076 | public var screenViewY: CGFloat { 1077 | get { 1078 | var y: CGFloat = 0 1079 | var view: UIView? = self 1080 | for (view; view == nil; view?.superview) { 1081 | y += view!.top 1082 | if view!.isKindOfClass(UIScrollView) { 1083 | var scrollView: UIScrollView = view as! UIScrollView 1084 | y -= scrollView.contentOffset.y 1085 | } 1086 | } 1087 | return y 1088 | } 1089 | } 1090 | 1091 | public var screenFrame: CGRect { 1092 | get { 1093 | return CGRectMake(self.screenViewX, self.screenViewY, self.width, self.height) 1094 | } 1095 | } 1096 | 1097 | public var origin: CGPoint { 1098 | get { 1099 | return self.frame.origin 1100 | } 1101 | set { 1102 | var frame: CGRect = self.frame 1103 | frame.origin = newValue 1104 | self.frame = frame 1105 | } 1106 | } 1107 | 1108 | public var size: CGSize { 1109 | get { 1110 | return self.frame.size 1111 | } 1112 | set { 1113 | var frame: CGRect = self.frame 1114 | frame.size = newValue 1115 | self.frame = frame 1116 | } 1117 | } 1118 | 1119 | public var allSubviews: NSArray { 1120 | get { 1121 | var arr: NSMutableArray = [] 1122 | arr.addObject(self) 1123 | for subView in self.subviews { 1124 | arr.addObjectsFromArray(subView.allSubviews! as [AnyObject]) 1125 | } 1126 | return arr 1127 | } 1128 | } 1129 | } 1130 | -------------------------------------------------------------------------------- /AirbnbViewControllerTests/AirbnbViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirbnbViewControllerTests.swift 3 | // AirbnbViewControllerTests 4 | // 5 | // Created by pixyzehn on 1/1/15. 6 | // Copyright (c) 2015 pixyzehn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class AirbnbViewControllerTests: 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 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AirbnbViewControllerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | pixyzehn.$(PRODUCT_NAME:rfc1034identifier) 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 | -------------------------------------------------------------------------------- /Assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixyzehn/AirbnbViewController/d6843c3660c3399cc0858bb000d18c3fbbb534df/Assets/demo.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nagasawa Hiroki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Notice: AirbnbViewController is no longer being maintained/updated.** 2 | 3 | AirbnbViewController 4 | ==================== 5 | 6 | Airbnb version 4.7's three-dimensional slide menu in Swift. Unfortunately, the menu was obsoleted in Airbnb version 5.0. In order not to forget the legend menu, I developed it in Swift. 7 | 8 | Inspired by https://github.com/TaPhuocHai/PHAirViewController. 9 | 10 | Overview 11 | ## Description 12 | 13 | Storyboard is not supported. You need to write code. 14 | I have no choice but to use Objective-C in a part of whole. 15 | 16 | ## Demo 17 | 18 | ![AirbnbViewController](https://github.com/pixyzehn/AirbnbViewController/blob/master/Assets/demo.gif) 19 | 20 | ## Installation 21 | 22 | The easiest way to get started is to use [CocoaPods](http://cocoapods.org/). Add the following line to your Podfile: 23 | 24 | ```ruby 25 | platform :ios, '8.0' 26 | # The following is a Library of Swift. 27 | use_frameworks! 28 | pod 'AirbnbViewController' 29 | ``` 30 | 31 | Then, run the following command: 32 | 33 | ```ruby 34 | pod install 35 | ``` 36 | 37 | And then, you need to have [project-name]-Bridging-Header.h because AirbnbViewController use Objective-C file. 38 | 39 | The easiest way to create a bridging header file is to add an arbitrary Objective-C file to your project and let Xcode create the bridging header for you. 40 | Delete the original Objective-C file as you no longer need it. 41 | 42 | [project-name]-Bridging-Header.h 43 | 44 | ```objc 45 | #import "AirbnbHelper.h" 46 | ``` 47 | 48 | Please refer to AirbnbViewController-Sample project. 49 | 50 | ## Licence 51 | 52 | [MIT](https://github.com/pixyzehn/AirbnbViewController/blob/master/LICENSE) 53 | 54 | ## Author 55 | 56 | [pixyzehn](https://github.com/pixyzehn) 57 | --------------------------------------------------------------------------------