├── .gitignore ├── LICENSE ├── PBPagerViewController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── paoloboschini.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── paoloboschini.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── PBPagerViewController.xcscheme │ └── xcschememanagement.plist ├── PBPagerViewController ├── AppDelegate.swift ├── ExampleViewController.swift ├── ExampleViewController.xib ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Launch Screen.xib └── PBPagerViewController.swift ├── PBPagerViewControllerTests ├── Info.plist └── PBPagerViewControllerTests.swift ├── README.md └── screen.gif /.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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Paolo Boschini 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 | -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 87C5FBFE1AD2EB1100284197 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C5FBFD1AD2EB1100284197 /* AppDelegate.swift */; }; 11 | 87C5FC001AD2EB1100284197 /* PBPagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C5FBFF1AD2EB1100284197 /* PBPagerViewController.swift */; }; 12 | 87C5FC051AD2EB1100284197 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 87C5FC041AD2EB1100284197 /* Images.xcassets */; }; 13 | 87C5FC141AD2EB1100284197 /* PBPagerViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C5FC131AD2EB1100284197 /* PBPagerViewControllerTests.swift */; }; 14 | 87C5FC211AD2EEC000284197 /* ExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87C5FC1F1AD2EEC000284197 /* ExampleViewController.swift */; }; 15 | 87C5FC221AD2EEC000284197 /* ExampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87C5FC201AD2EEC000284197 /* ExampleViewController.xib */; }; 16 | 87C5FC261AD33F1500284197 /* Launch Screen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87C5FC251AD33F1500284197 /* Launch Screen.xib */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 87C5FC0E1AD2EB1100284197 /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 87C5FBF01AD2EB1100284197 /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 87C5FBF71AD2EB1100284197; 25 | remoteInfo = PBPagerViewController; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 87C5FBF81AD2EB1100284197 /* PBPagerViewController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PBPagerViewController.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 87C5FBFC1AD2EB1100284197 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 87C5FBFD1AD2EB1100284197 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33 | 87C5FBFF1AD2EB1100284197 /* PBPagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PBPagerViewController.swift; sourceTree = ""; }; 34 | 87C5FC041AD2EB1100284197 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 35 | 87C5FC0D1AD2EB1100284197 /* PBPagerViewControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PBPagerViewControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 87C5FC121AD2EB1100284197 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 87C5FC131AD2EB1100284197 /* PBPagerViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PBPagerViewControllerTests.swift; sourceTree = ""; }; 38 | 87C5FC1F1AD2EEC000284197 /* ExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleViewController.swift; sourceTree = ""; }; 39 | 87C5FC201AD2EEC000284197 /* ExampleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ExampleViewController.xib; sourceTree = ""; }; 40 | 87C5FC251AD33F1500284197 /* Launch Screen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "Launch Screen.xib"; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 87C5FBF51AD2EB1100284197 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | 87C5FC0A1AD2EB1100284197 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 87C5FBEF1AD2EB1100284197 = { 62 | isa = PBXGroup; 63 | children = ( 64 | 87C5FBFA1AD2EB1100284197 /* PBPagerViewController */, 65 | 87C5FC101AD2EB1100284197 /* PBPagerViewControllerTests */, 66 | 87C5FBF91AD2EB1100284197 /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 87C5FBF91AD2EB1100284197 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 87C5FBF81AD2EB1100284197 /* PBPagerViewController.app */, 74 | 87C5FC0D1AD2EB1100284197 /* PBPagerViewControllerTests.xctest */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 87C5FBFA1AD2EB1100284197 /* PBPagerViewController */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 87C5FBFD1AD2EB1100284197 /* AppDelegate.swift */, 83 | 87C5FBFF1AD2EB1100284197 /* PBPagerViewController.swift */, 84 | 87C5FC1F1AD2EEC000284197 /* ExampleViewController.swift */, 85 | 87C5FC201AD2EEC000284197 /* ExampleViewController.xib */, 86 | 87C5FC041AD2EB1100284197 /* Images.xcassets */, 87 | 87C5FC251AD33F1500284197 /* Launch Screen.xib */, 88 | 87C5FBFB1AD2EB1100284197 /* Supporting Files */, 89 | ); 90 | path = PBPagerViewController; 91 | sourceTree = ""; 92 | }; 93 | 87C5FBFB1AD2EB1100284197 /* Supporting Files */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 87C5FBFC1AD2EB1100284197 /* Info.plist */, 97 | ); 98 | name = "Supporting Files"; 99 | sourceTree = ""; 100 | }; 101 | 87C5FC101AD2EB1100284197 /* PBPagerViewControllerTests */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 87C5FC131AD2EB1100284197 /* PBPagerViewControllerTests.swift */, 105 | 87C5FC111AD2EB1100284197 /* Supporting Files */, 106 | ); 107 | path = PBPagerViewControllerTests; 108 | sourceTree = ""; 109 | }; 110 | 87C5FC111AD2EB1100284197 /* Supporting Files */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 87C5FC121AD2EB1100284197 /* Info.plist */, 114 | ); 115 | name = "Supporting Files"; 116 | sourceTree = ""; 117 | }; 118 | /* End PBXGroup section */ 119 | 120 | /* Begin PBXNativeTarget section */ 121 | 87C5FBF71AD2EB1100284197 /* PBPagerViewController */ = { 122 | isa = PBXNativeTarget; 123 | buildConfigurationList = 87C5FC171AD2EB1100284197 /* Build configuration list for PBXNativeTarget "PBPagerViewController" */; 124 | buildPhases = ( 125 | 87C5FBF41AD2EB1100284197 /* Sources */, 126 | 87C5FBF51AD2EB1100284197 /* Frameworks */, 127 | 87C5FBF61AD2EB1100284197 /* Resources */, 128 | ); 129 | buildRules = ( 130 | ); 131 | dependencies = ( 132 | ); 133 | name = PBPagerViewController; 134 | productName = PBPagerViewController; 135 | productReference = 87C5FBF81AD2EB1100284197 /* PBPagerViewController.app */; 136 | productType = "com.apple.product-type.application"; 137 | }; 138 | 87C5FC0C1AD2EB1100284197 /* PBPagerViewControllerTests */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 87C5FC1A1AD2EB1100284197 /* Build configuration list for PBXNativeTarget "PBPagerViewControllerTests" */; 141 | buildPhases = ( 142 | 87C5FC091AD2EB1100284197 /* Sources */, 143 | 87C5FC0A1AD2EB1100284197 /* Frameworks */, 144 | 87C5FC0B1AD2EB1100284197 /* Resources */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | 87C5FC0F1AD2EB1100284197 /* PBXTargetDependency */, 150 | ); 151 | name = PBPagerViewControllerTests; 152 | productName = PBPagerViewControllerTests; 153 | productReference = 87C5FC0D1AD2EB1100284197 /* PBPagerViewControllerTests.xctest */; 154 | productType = "com.apple.product-type.bundle.unit-test"; 155 | }; 156 | /* End PBXNativeTarget section */ 157 | 158 | /* Begin PBXProject section */ 159 | 87C5FBF01AD2EB1100284197 /* Project object */ = { 160 | isa = PBXProject; 161 | attributes = { 162 | LastUpgradeCheck = 0620; 163 | ORGANIZATIONNAME = "Paolo Boschini"; 164 | TargetAttributes = { 165 | 87C5FBF71AD2EB1100284197 = { 166 | CreatedOnToolsVersion = 6.2; 167 | }; 168 | 87C5FC0C1AD2EB1100284197 = { 169 | CreatedOnToolsVersion = 6.2; 170 | TestTargetID = 87C5FBF71AD2EB1100284197; 171 | }; 172 | }; 173 | }; 174 | buildConfigurationList = 87C5FBF31AD2EB1100284197 /* Build configuration list for PBXProject "PBPagerViewController" */; 175 | compatibilityVersion = "Xcode 3.2"; 176 | developmentRegion = English; 177 | hasScannedForEncodings = 0; 178 | knownRegions = ( 179 | en, 180 | Base, 181 | ); 182 | mainGroup = 87C5FBEF1AD2EB1100284197; 183 | productRefGroup = 87C5FBF91AD2EB1100284197 /* Products */; 184 | projectDirPath = ""; 185 | projectRoot = ""; 186 | targets = ( 187 | 87C5FBF71AD2EB1100284197 /* PBPagerViewController */, 188 | 87C5FC0C1AD2EB1100284197 /* PBPagerViewControllerTests */, 189 | ); 190 | }; 191 | /* End PBXProject section */ 192 | 193 | /* Begin PBXResourcesBuildPhase section */ 194 | 87C5FBF61AD2EB1100284197 /* Resources */ = { 195 | isa = PBXResourcesBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | 87C5FC221AD2EEC000284197 /* ExampleViewController.xib in Resources */, 199 | 87C5FC261AD33F1500284197 /* Launch Screen.xib in Resources */, 200 | 87C5FC051AD2EB1100284197 /* Images.xcassets in Resources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | 87C5FC0B1AD2EB1100284197 /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXResourcesBuildPhase section */ 212 | 213 | /* Begin PBXSourcesBuildPhase section */ 214 | 87C5FBF41AD2EB1100284197 /* Sources */ = { 215 | isa = PBXSourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | 87C5FC001AD2EB1100284197 /* PBPagerViewController.swift in Sources */, 219 | 87C5FBFE1AD2EB1100284197 /* AppDelegate.swift in Sources */, 220 | 87C5FC211AD2EEC000284197 /* ExampleViewController.swift in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | 87C5FC091AD2EB1100284197 /* Sources */ = { 225 | isa = PBXSourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 87C5FC141AD2EB1100284197 /* PBPagerViewControllerTests.swift in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin PBXTargetDependency section */ 235 | 87C5FC0F1AD2EB1100284197 /* PBXTargetDependency */ = { 236 | isa = PBXTargetDependency; 237 | target = 87C5FBF71AD2EB1100284197 /* PBPagerViewController */; 238 | targetProxy = 87C5FC0E1AD2EB1100284197 /* PBXContainerItemProxy */; 239 | }; 240 | /* End PBXTargetDependency section */ 241 | 242 | /* Begin XCBuildConfiguration section */ 243 | 87C5FC151AD2EB1100284197 /* Debug */ = { 244 | isa = XCBuildConfiguration; 245 | buildSettings = { 246 | ALWAYS_SEARCH_USER_PATHS = NO; 247 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 248 | CLANG_CXX_LIBRARY = "libc++"; 249 | CLANG_ENABLE_MODULES = YES; 250 | CLANG_ENABLE_OBJC_ARC = YES; 251 | CLANG_WARN_BOOL_CONVERSION = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 258 | CLANG_WARN_UNREACHABLE_CODE = YES; 259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 260 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 261 | COPY_PHASE_STRIP = NO; 262 | ENABLE_STRICT_OBJC_MSGSEND = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_DYNAMIC_NO_PIC = NO; 265 | GCC_OPTIMIZATION_LEVEL = 0; 266 | GCC_PREPROCESSOR_DEFINITIONS = ( 267 | "DEBUG=1", 268 | "$(inherited)", 269 | ); 270 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 278 | MTL_ENABLE_DEBUG_INFO = YES; 279 | ONLY_ACTIVE_ARCH = YES; 280 | SDKROOT = iphoneos; 281 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 282 | }; 283 | name = Debug; 284 | }; 285 | 87C5FC161AD2EB1100284197 /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INT_CONVERSION = YES; 299 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 300 | CLANG_WARN_UNREACHABLE_CODE = YES; 301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 302 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 303 | COPY_PHASE_STRIP = NO; 304 | ENABLE_NS_ASSERTIONS = NO; 305 | ENABLE_STRICT_OBJC_MSGSEND = YES; 306 | GCC_C_LANGUAGE_STANDARD = gnu99; 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 8.2; 314 | MTL_ENABLE_DEBUG_INFO = NO; 315 | SDKROOT = iphoneos; 316 | VALIDATE_PRODUCT = YES; 317 | }; 318 | name = Release; 319 | }; 320 | 87C5FC181AD2EB1100284197 /* Debug */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | INFOPLIST_FILE = PBPagerViewController/Info.plist; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | PRODUCT_NAME = "$(TARGET_NAME)"; 327 | }; 328 | name = Debug; 329 | }; 330 | 87C5FC191AD2EB1100284197 /* Release */ = { 331 | isa = XCBuildConfiguration; 332 | buildSettings = { 333 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 334 | INFOPLIST_FILE = PBPagerViewController/Info.plist; 335 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | }; 338 | name = Release; 339 | }; 340 | 87C5FC1B1AD2EB1100284197 /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | BUNDLE_LOADER = "$(TEST_HOST)"; 344 | FRAMEWORK_SEARCH_PATHS = ( 345 | "$(SDKROOT)/Developer/Library/Frameworks", 346 | "$(inherited)", 347 | ); 348 | GCC_PREPROCESSOR_DEFINITIONS = ( 349 | "DEBUG=1", 350 | "$(inherited)", 351 | ); 352 | INFOPLIST_FILE = PBPagerViewControllerTests/Info.plist; 353 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PBPagerViewController.app/PBPagerViewController"; 356 | }; 357 | name = Debug; 358 | }; 359 | 87C5FC1C1AD2EB1100284197 /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | buildSettings = { 362 | BUNDLE_LOADER = "$(TEST_HOST)"; 363 | FRAMEWORK_SEARCH_PATHS = ( 364 | "$(SDKROOT)/Developer/Library/Frameworks", 365 | "$(inherited)", 366 | ); 367 | INFOPLIST_FILE = PBPagerViewControllerTests/Info.plist; 368 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 369 | PRODUCT_NAME = "$(TARGET_NAME)"; 370 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PBPagerViewController.app/PBPagerViewController"; 371 | }; 372 | name = Release; 373 | }; 374 | /* End XCBuildConfiguration section */ 375 | 376 | /* Begin XCConfigurationList section */ 377 | 87C5FBF31AD2EB1100284197 /* Build configuration list for PBXProject "PBPagerViewController" */ = { 378 | isa = XCConfigurationList; 379 | buildConfigurations = ( 380 | 87C5FC151AD2EB1100284197 /* Debug */, 381 | 87C5FC161AD2EB1100284197 /* Release */, 382 | ); 383 | defaultConfigurationIsVisible = 0; 384 | defaultConfigurationName = Release; 385 | }; 386 | 87C5FC171AD2EB1100284197 /* Build configuration list for PBXNativeTarget "PBPagerViewController" */ = { 387 | isa = XCConfigurationList; 388 | buildConfigurations = ( 389 | 87C5FC181AD2EB1100284197 /* Debug */, 390 | 87C5FC191AD2EB1100284197 /* Release */, 391 | ); 392 | defaultConfigurationIsVisible = 0; 393 | defaultConfigurationName = Release; 394 | }; 395 | 87C5FC1A1AD2EB1100284197 /* Build configuration list for PBXNativeTarget "PBPagerViewControllerTests" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | 87C5FC1B1AD2EB1100284197 /* Debug */, 399 | 87C5FC1C1AD2EB1100284197 /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | /* End XCConfigurationList section */ 405 | }; 406 | rootObject = 87C5FBF01AD2EB1100284197 /* Project object */; 407 | } 408 | -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/project.xcworkspace/xcuserdata/paoloboschini.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paoloboschini/PBPagerViewController/7297ae0522bc5a0a93909e6ec1434f9152753c3b/PBPagerViewController.xcodeproj/project.xcworkspace/xcuserdata/paoloboschini.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/xcuserdata/paoloboschini.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/xcuserdata/paoloboschini.xcuserdatad/xcschemes/PBPagerViewController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /PBPagerViewController.xcodeproj/xcuserdata/paoloboschini.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PBPagerViewController.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 87C5FBF71AD2EB1100284197 16 | 17 | primary 18 | 19 | 20 | 87C5FC0C1AD2EB1100284197 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PBPagerViewController/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PBPagerViewController 4 | // 5 | // Created by Paolo Boschini on 06/04/15. 6 | // Copyright (c) 2015 Paolo Boschini. 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 | 18 | let vc1 = ExampleViewController() 19 | vc1.view.backgroundColor = UIColor.redColor() 20 | let tuple1: (String, UIViewController) = (vc1.title!, vc1) 21 | 22 | var vc2 = ExampleViewController() 23 | vc2.view.backgroundColor = UIColor.greenColor() 24 | let tuple2: (String, UIViewController) = ("CustomTitle", vc2) 25 | 26 | var vc3 = ExampleViewController() 27 | vc3.view.backgroundColor = UIColor.yellowColor() 28 | let tuple3: (String, UIViewController) = ("Third VC", vc3) 29 | 30 | let pages: [(String, UIViewController)] = [tuple1, tuple2, tuple3] 31 | let pbPager = PBPagerViewController(pages: pages) 32 | let nc = UINavigationController(rootViewController: pbPager) 33 | // let nc = UINavigationController(rootViewController: PBPagerViewController(pages: pages, backgroundColor: UIColor.lightGrayColor(), titleColor: UIColor.darkGrayColor(), gradientLocations: [0.2, 0.3, 0.7, 0.8])) 34 | 35 | vc1.parent = pbPager 36 | vc2.parent = pbPager 37 | vc3.parent = pbPager 38 | 39 | window = UIWindow(frame: UIScreen.mainScreen().bounds) 40 | window?.rootViewController = nc 41 | window?.makeKeyAndVisible() 42 | return true 43 | } 44 | 45 | func applicationWillResignActive(application: UIApplication) { 46 | } 47 | 48 | func applicationDidEnterBackground(application: UIApplication) { 49 | } 50 | 51 | func applicationWillEnterForeground(application: UIApplication) { 52 | } 53 | 54 | func applicationDidBecomeActive(application: UIApplication) { 55 | } 56 | 57 | func applicationWillTerminate(application: UIApplication) { 58 | } 59 | } -------------------------------------------------------------------------------- /PBPagerViewController/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.swift 3 | // PBPagerViewController 4 | // 5 | // Created by Paolo Boschini on 06/04/15. 6 | // Copyright (c) 2015 Paolo Boschini. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ExampleViewController: UIViewController { 12 | 13 | @IBOutlet var l1: UILabel! 14 | @IBOutlet var l2: UILabel! 15 | @IBOutlet var l3: UILabel! 16 | @IBOutlet var l4: UILabel! 17 | 18 | @IBOutlet var s1: UISlider! 19 | @IBOutlet var s2: UISlider! 20 | @IBOutlet var s3: UISlider! 21 | @IBOutlet var s4: UISlider! 22 | 23 | var parent: PBPagerViewController! 24 | 25 | init() { 26 | super.init(nibName: "ExampleViewController", bundle: nil) 27 | title = "ViewControllerTitle" 28 | } 29 | 30 | required init(coder aDecoder: NSCoder) { 31 | super.init(coder: aDecoder) 32 | } 33 | 34 | override func viewDidLoad() { 35 | l1.text = "\(s1.value)" 36 | l2.text = "\(s2.value)" 37 | l3.text = "\(s3.value)" 38 | l4.text = "\(s4.value)" 39 | } 40 | 41 | @IBAction func sliderChanged(slider: UISlider) { 42 | var label = self.view.viewWithTag(slider.tag + 1) as! UILabel 43 | label.text = "\(slider.value)" 44 | for page in parent.pages { 45 | let vc = page as! ExampleViewController 46 | vc.s1.value = s1.value 47 | vc.s2.value = s2.value 48 | vc.s3.value = s3.value 49 | vc.s4.value = s4.value 50 | vc.l1.text = l1.text 51 | vc.l2.text = l2.text 52 | vc.l3.text = l3.text 53 | vc.l4.text = l4.text 54 | } 55 | parent.hMaskLayer.locations = [s1.value, s2.value, s3.value, s4.value] 56 | } 57 | } -------------------------------------------------------------------------------- /PBPagerViewController/ExampleViewController.xib: -------------------------------------------------------------------------------- 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 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /PBPagerViewController/Images.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 | } -------------------------------------------------------------------------------- /PBPagerViewController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | Paolo-Boschini.$(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 | Launch Screen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /PBPagerViewController/Launch Screen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /PBPagerViewController/PBPagerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PBPagerViewController 4 | // 5 | // Created by Paolo Boschini on 06/04/15. 6 | // Copyright (c) 2015 Paolo Boschini. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIViewController : Equatable {} 12 | 13 | public func == (v1: UIViewController, v2: UIViewController) -> Bool { 14 | return v1.isEqual(v2) 15 | } 16 | 17 | class PBPagerViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate { 18 | 19 | var pageController: UIPageViewController! 20 | var titleScrollView: UIScrollView! 21 | var pages: [UIViewController]! 22 | var titles: [String]! 23 | var currentIndex: Int! 24 | var backgroundColor: UIColor! 25 | var titleColor: UIColor! 26 | var screenWidth: CGFloat! 27 | var navbar: UINavigationBar! 28 | var gradientLocations: [CGFloat]! 29 | 30 | convenience init(pages: [(String, UIViewController)]) { 31 | let summerSkyColor = UIColor(red: 77/255, green: 174/255, blue: 232/255, alpha: 1) 32 | let titleColor = UIColor.whiteColor() 33 | self.init(pages: pages, backgroundColor: summerSkyColor, titleColor: titleColor, gradientLocations: [0, 0.2, 0.8, 1]) 34 | } 35 | 36 | init(pages: [(String, UIViewController)], backgroundColor: UIColor, titleColor: UIColor = UIColor.whiteColor(), gradientLocations: [CGFloat]) { 37 | super.init(nibName: nil, bundle: nil) 38 | UINavigationBar.appearance().barTintColor = backgroundColor 39 | UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent 40 | self.titles = pages.map { tuple -> String in tuple.0 } 41 | self.pages = pages.map { tuple -> UIViewController in tuple.1 } 42 | self.backgroundColor = backgroundColor 43 | self.titleColor = titleColor 44 | self.gradientLocations = gradientLocations 45 | } 46 | 47 | required init(coder aDecoder: NSCoder) { 48 | super.init(coder: aDecoder) 49 | } 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | screenWidth = UIScreen.mainScreen().bounds.size.width 55 | navbar = navigationController?.navigationBar 56 | 57 | setUpPageViewController() 58 | setUpTitleScrollView() 59 | setUpGradients() 60 | setUpLabels() 61 | 62 | let viewControllers = [pages[0]] 63 | pageController.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil) 64 | } 65 | 66 | func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { 67 | let index = find(pages, viewController) 68 | return index! == 0 ? nil : pages[index! - 1] 69 | } 70 | 71 | func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { 72 | let index = find(pages, viewController) 73 | return index! + 1 == pages.count ? nil : pages[index! + 1] 74 | } 75 | 76 | func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) { 77 | if completed { 78 | let index = find(pages, pageController.viewControllers[0] as! UIViewController) 79 | currentIndex = index 80 | } 81 | } 82 | 83 | func scrollViewDidScroll(scrollView: UIScrollView) { 84 | currentIndex = currentIndex == nil ? 0 : currentIndex 85 | let width: Int = Int(view.bounds.size.width) 86 | let xOffset: Int = Int(scrollView.contentOffset.x) 87 | let scrolledAmount: Int = xOffset - width + (currentIndex * width) 88 | titleScrollView.setContentOffset(CGPointMake(CGFloat(scrolledAmount)/2, 0), animated: false) 89 | } 90 | 91 | private func setUpPageViewController() { 92 | pageController = UIPageViewController(transitionStyle: UIPageViewControllerTransitionStyle.Scroll, navigationOrientation: UIPageViewControllerNavigationOrientation.Horizontal, options: nil) 93 | pageController.delegate = self 94 | pageController.dataSource = self 95 | pageController.view.frame = view.bounds 96 | view.addSubview(pageController.view) 97 | 98 | pageController.view.subviews.map { view -> () in 99 | if view is UIScrollView { 100 | (view as! UIScrollView).delegate = self 101 | } 102 | } 103 | } 104 | 105 | private func setUpTitleScrollView() { 106 | let rect: CGRect = CGRectMake(0, 0, CGFloat(screenWidth), navbar.frame.size.height) 107 | titleScrollView = UIScrollView(frame: rect) 108 | titleScrollView.contentSize = CGSizeMake(screenWidth, navbar.frame.size.height) 109 | titleScrollView.backgroundColor = backgroundColor 110 | navigationController?.navigationBar.addSubview(titleScrollView) 111 | } 112 | 113 | var hMaskLayer: CAGradientLayer! 114 | private func setUpGradients() { 115 | let stop0 = backgroundColor.colorWithAlphaComponent(1).CGColor 116 | let stop1 = backgroundColor.colorWithAlphaComponent(0).CGColor 117 | 118 | // horizontal gradient (left/right edges) 119 | hMaskLayer = CAGradientLayer() 120 | hMaskLayer.opacity = 1 121 | hMaskLayer.colors = [stop0, stop1, stop1, stop0] 122 | hMaskLayer.locations = gradientLocations 123 | hMaskLayer.startPoint = CGPointMake(0, 0) 124 | hMaskLayer.endPoint = CGPointMake(1.0, 0) 125 | hMaskLayer.bounds = navbar.bounds 126 | hMaskLayer.anchorPoint = CGPointZero; 127 | 128 | navbar.layer.addSublayer(hMaskLayer) 129 | navbar.titleTextAttributes = [NSForegroundColorAttributeName: backgroundColor.colorWithAlphaComponent(0)] 130 | navbar.backgroundColor = backgroundColor.colorWithAlphaComponent(0) 131 | navbar.tintColor = titleColor 132 | navbar.translucent = false 133 | } 134 | 135 | private func setUpLabels() { 136 | for i in 0.. 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | Paolo-Boschini.$(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 | -------------------------------------------------------------------------------- /PBPagerViewControllerTests/PBPagerViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PBPagerViewControllerTests.swift 3 | // PBPagerViewControllerTests 4 | // 5 | // Created by Paolo Boschini on 06/04/15. 6 | // Copyright (c) 2015 Paolo Boschini. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class PBPagerViewControllerTests: 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PBPagerViewController 2 | ==== 3 | 4 | A Swifty Pager View Controller 5 | 6 | ![alt tag](screen.gif) 7 | 8 | Basic Usage 9 | ======== 10 | 11 | See example project for a demo. 12 | 13 | ```swift 14 | // In your app delegate 15 | 16 | // Create first view controller with title 17 | let vc1 = ExampleViewController() 18 | vc1.view.backgroundColor = UIColor.redColor() 19 | let tuple1: (String, UIViewController) = (vc1.title!, vc1) 20 | 21 | // Create second view controller with title 22 | var vc2 = ExampleViewController() 23 | vc2.view.backgroundColor = UIColor.greenColor() 24 | let tuple2: (String, UIViewController) = ("CustomTitle", vc2) 25 | 26 | // Create third view controller with title 27 | var vc3 = ExampleViewController() 28 | vc3.view.backgroundColor = UIColor.yellowColor() 29 | let tuple3: (String, UIViewController) = ("Third VC", vc3) 30 | 31 | // Create pages 32 | let pages: [(String, UIViewController)] = [tuple1, tuple2, tuple3] 33 | 34 | // Create default pager... 35 | let pbPager = PBPagerViewController(pages: pages) 36 | 37 | // ...or custom pager 38 | let pbPager = PBPagerViewController(pages: pages, backgroundColor: UIColor.lightGrayColor(), titleColor: UIColor.darkGrayColor(), gradientLocations: [0.2, 0.3, 0.7, 0.8]) 39 | 40 | // Set navigation controller 41 | let nc = UINavigationController(rootViewController: pbPager) 42 | 43 | 44 | ``` 45 | -------------------------------------------------------------------------------- /screen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paoloboschini/PBPagerViewController/7297ae0522bc5a0a93909e6ec1434f9152753c3b/screen.gif --------------------------------------------------------------------------------