├── .gitignore ├── LICENSE ├── PWParallaxScrollView.podspec ├── PWParallaxScrollView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── PWParallaxScrollView.xccheckout │ └── xcuserdata │ │ └── wpsteak.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── wpsteak.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── PWParallaxScrollView.xcscheme │ ├── PWParallaxScrollView_ObjCUseSwift.xcscheme │ └── xcschememanagement.plist ├── PWParallaxScrollView ├── PWParallaxScrollView.h ├── PWParallaxScrollView.m └── PWParallaxScrollView.swift ├── PWParallaxScrollViewExample ├── AppDelegate.h ├── AppDelegate.m ├── Images │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── LaunchScreen.storyboard ├── PWParallaxScrollView-Info.plist ├── PWParallaxScrollView-Prefix.pch ├── PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h ├── ViewController.h ├── ViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── ViewController.xib └── main.m ├── README.md ├── gif ├── edgeinsets.gif ├── edgeinsets1.gif ├── screenshot.gif ├── screenshot1.gif ├── screenshot3.gif └── screenshot4.gif └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | # Pods/ 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pin Shih Wang 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. -------------------------------------------------------------------------------- /PWParallaxScrollView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PWParallaxScrollView" 3 | s.version = "1.2.0" 4 | s.summary = "PWParallaxScrollView is a library for creating sliding menus with parallax effect inspired by the WWF app" 5 | s.homepage = "http://www.github.com/wpsteak/PWParallaxScrollView" 6 | s.screenshots = "https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/screenshot.png" 7 | s.license = { :type => 'MIT', :file => 'LICENSE' } 8 | s.author = { "wpsteak" => "wpsteak@gmail.com" } 9 | s.platform = :ios ,'8.0' 10 | s.default_subspec = 'ObjC' 11 | s.source = { 12 | :git => "https://github.com/wpsteak/PWParallaxScrollView.git", 13 | :tag => s.version 14 | } 15 | 16 | s.subspec 'ObjC' do |ss| 17 | ss.source_files = 'PWParallaxScrollView/*.{h,m}' 18 | ss.public_header_files = 'PWParallaxScrollView/*.h' 19 | end 20 | 21 | s.subspec 'Swift' do |ss| 22 | ss.ios.deployment_target = '8.0' 23 | ss.source_files = 'PWParallaxScrollView/*.swift' 24 | end 25 | 26 | 27 | end 28 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F431D3B31C65E175009F5851 /* PWParallaxScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F431D3B21C65E175009F5851 /* PWParallaxScrollView.swift */; }; 11 | F431D3B51C65E2A9009F5851 /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C2418ECEF220078CB10 /* ViewController.xib */; }; 12 | F431D3B61C65E3A2009F5851 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C1C18ECEF220078CB10 /* AppDelegate.m */; }; 13 | F431D3B71C65E3D4009F5851 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C2618ECEF220078CB10 /* main.m */; }; 14 | F431D3B81C65E44D009F5851 /* 1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3C18ECEFA50078CB10 /* 1.jpg */; }; 15 | F431D3B91C65E44D009F5851 /* 2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3D18ECEFA50078CB10 /* 2.jpg */; }; 16 | F431D3BA1C65E44D009F5851 /* 3.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3E18ECEFA50078CB10 /* 3.jpg */; }; 17 | F431D3BB1C65E44D009F5851 /* 4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3F18ECEFA50078CB10 /* 4.jpg */; }; 18 | F431D3BC1C65E44D009F5851 /* 5.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C4018ECEFA50078CB10 /* 5.jpg */; }; 19 | F431D3BD1C65E44D009F5851 /* 6.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C4118ECEFA50078CB10 /* 6.jpg */; }; 20 | F431D3BF1C65E532009F5851 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F431D3BE1C65E532009F5851 /* LaunchScreen.storyboard */; }; 21 | F431D3C01C65E532009F5851 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F431D3BE1C65E532009F5851 /* LaunchScreen.storyboard */; }; 22 | F47F3C581C65FAEF0042CF2E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C2A18ECEF220078CB10 /* ViewController.m */; }; 23 | F497D91D17DC93EF007DE2EC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F497D91C17DC93EF007DE2EC /* UIKit.framework */; }; 24 | F497D91F17DC93EF007DE2EC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F497D91E17DC93EF007DE2EC /* Foundation.framework */; }; 25 | F4E98C1318ECEE450078CB10 /* PWParallaxScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C1218ECEE450078CB10 /* PWParallaxScrollView.m */; }; 26 | F4E98C3118ECEF220078CB10 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C1C18ECEF220078CB10 /* AppDelegate.m */; }; 27 | F4E98C3518ECEF220078CB10 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C2018ECEF220078CB10 /* InfoPlist.strings */; }; 28 | F4E98C3718ECEF220078CB10 /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C2418ECEF220078CB10 /* ViewController.xib */; }; 29 | F4E98C3818ECEF220078CB10 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C2618ECEF220078CB10 /* main.m */; }; 30 | F4E98C3A18ECEF220078CB10 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F4E98C2A18ECEF220078CB10 /* ViewController.m */; }; 31 | F4E98C4218ECEFA50078CB10 /* 1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3C18ECEFA50078CB10 /* 1.jpg */; }; 32 | F4E98C4318ECEFA50078CB10 /* 2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3D18ECEFA50078CB10 /* 2.jpg */; }; 33 | F4E98C4418ECEFA50078CB10 /* 3.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3E18ECEFA50078CB10 /* 3.jpg */; }; 34 | F4E98C4518ECEFA50078CB10 /* 4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C3F18ECEFA50078CB10 /* 4.jpg */; }; 35 | F4E98C4618ECEFA50078CB10 /* 5.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C4018ECEFA50078CB10 /* 5.jpg */; }; 36 | F4E98C4718ECEFA50078CB10 /* 6.jpg in Resources */ = {isa = PBXBuildFile; fileRef = F4E98C4118ECEFA50078CB10 /* 6.jpg */; }; 37 | F4E98C4918ECF01D0078CB10 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F497D92017DC93EF007DE2EC /* CoreGraphics.framework */; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | F431D3911C65DE7E009F5851 /* PWParallaxScrollView_ObjCUseSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PWParallaxScrollView_ObjCUseSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | F431D3B11C65E174009F5851 /* PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h"; path = "PWParallaxScrollViewExample/PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h"; sourceTree = SOURCE_ROOT; }; 43 | F431D3B21C65E175009F5851 /* PWParallaxScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PWParallaxScrollView.swift; path = PWParallaxScrollView/PWParallaxScrollView.swift; sourceTree = SOURCE_ROOT; }; 44 | F431D3BE1C65E532009F5851 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 45 | F497D91917DC93EF007DE2EC /* PWParallaxScrollView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PWParallaxScrollView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | F497D91C17DC93EF007DE2EC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 47 | F497D91E17DC93EF007DE2EC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 48 | F497D92017DC93EF007DE2EC /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 49 | F4E98C1118ECEE450078CB10 /* PWParallaxScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PWParallaxScrollView.h; sourceTree = ""; }; 50 | F4E98C1218ECEE450078CB10 /* PWParallaxScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PWParallaxScrollView.m; sourceTree = ""; }; 51 | F4E98C1B18ECEF220078CB10 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 52 | F4E98C1C18ECEF220078CB10 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 53 | F4E98C2118ECEF220078CB10 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 54 | F4E98C2518ECEF220078CB10 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = ""; }; 55 | F4E98C2618ECEF220078CB10 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 56 | F4E98C2718ECEF220078CB10 /* PWParallaxScrollView-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "PWParallaxScrollView-Info.plist"; sourceTree = ""; }; 57 | F4E98C2818ECEF220078CB10 /* PWParallaxScrollView-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PWParallaxScrollView-Prefix.pch"; sourceTree = ""; }; 58 | F4E98C2918ECEF220078CB10 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 59 | F4E98C2A18ECEF220078CB10 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 60 | F4E98C3C18ECEFA50078CB10 /* 1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 1.jpg; sourceTree = ""; }; 61 | F4E98C3D18ECEFA50078CB10 /* 2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 2.jpg; sourceTree = ""; }; 62 | F4E98C3E18ECEFA50078CB10 /* 3.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 3.jpg; sourceTree = ""; }; 63 | F4E98C3F18ECEFA50078CB10 /* 4.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 4.jpg; sourceTree = ""; }; 64 | F4E98C4018ECEFA50078CB10 /* 5.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 5.jpg; sourceTree = ""; }; 65 | F4E98C4118ECEFA50078CB10 /* 6.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = 6.jpg; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | F431D38E1C65DE7E009F5851 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | F497D91617DC93EF007DE2EC /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | F4E98C4918ECF01D0078CB10 /* CoreGraphics.framework in Frameworks */, 81 | F497D91D17DC93EF007DE2EC /* UIKit.framework in Frameworks */, 82 | F497D91F17DC93EF007DE2EC /* Foundation.framework in Frameworks */, 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | /* End PBXFrameworksBuildPhase section */ 87 | 88 | /* Begin PBXGroup section */ 89 | F497D91017DC93EF007DE2EC = { 90 | isa = PBXGroup; 91 | children = ( 92 | F4E98C1018ECEE450078CB10 /* PWParallaxScrollView */, 93 | F4E98C1418ECEF220078CB10 /* PWParallaxScrollViewExample */, 94 | F4E98C4818ECEFAE0078CB10 /* Resources */, 95 | F497D91B17DC93EF007DE2EC /* Frameworks */, 96 | F497D91A17DC93EF007DE2EC /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | F497D91A17DC93EF007DE2EC /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | F497D91917DC93EF007DE2EC /* PWParallaxScrollView.app */, 104 | F431D3911C65DE7E009F5851 /* PWParallaxScrollView_ObjCUseSwift.app */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | F497D91B17DC93EF007DE2EC /* Frameworks */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | F497D91C17DC93EF007DE2EC /* UIKit.framework */, 113 | F497D91E17DC93EF007DE2EC /* Foundation.framework */, 114 | F497D92017DC93EF007DE2EC /* CoreGraphics.framework */, 115 | ); 116 | name = Frameworks; 117 | sourceTree = ""; 118 | }; 119 | F4E98C1018ECEE450078CB10 /* PWParallaxScrollView */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | F4E98C1118ECEE450078CB10 /* PWParallaxScrollView.h */, 123 | F4E98C1218ECEE450078CB10 /* PWParallaxScrollView.m */, 124 | F431D3B21C65E175009F5851 /* PWParallaxScrollView.swift */, 125 | ); 126 | path = PWParallaxScrollView; 127 | sourceTree = ""; 128 | }; 129 | F4E98C1418ECEF220078CB10 /* PWParallaxScrollViewExample */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | F431D3B11C65E174009F5851 /* PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h */, 133 | F4E98C1B18ECEF220078CB10 /* AppDelegate.h */, 134 | F4E98C1C18ECEF220078CB10 /* AppDelegate.m */, 135 | F4E98C2418ECEF220078CB10 /* ViewController.xib */, 136 | F4E98C2918ECEF220078CB10 /* ViewController.h */, 137 | F4E98C2A18ECEF220078CB10 /* ViewController.m */, 138 | ); 139 | path = PWParallaxScrollViewExample; 140 | sourceTree = ""; 141 | }; 142 | F4E98C3B18ECEFA50078CB10 /* Images */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | F4E98C3C18ECEFA50078CB10 /* 1.jpg */, 146 | F4E98C3D18ECEFA50078CB10 /* 2.jpg */, 147 | F4E98C3E18ECEFA50078CB10 /* 3.jpg */, 148 | F4E98C3F18ECEFA50078CB10 /* 4.jpg */, 149 | F4E98C4018ECEFA50078CB10 /* 5.jpg */, 150 | F4E98C4118ECEFA50078CB10 /* 6.jpg */, 151 | ); 152 | path = Images; 153 | sourceTree = ""; 154 | }; 155 | F4E98C4818ECEFAE0078CB10 /* Resources */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | F4E98C3B18ECEFA50078CB10 /* Images */, 159 | F431D3BE1C65E532009F5851 /* LaunchScreen.storyboard */, 160 | F4E98C2018ECEF220078CB10 /* InfoPlist.strings */, 161 | F4E98C2618ECEF220078CB10 /* main.m */, 162 | F4E98C2718ECEF220078CB10 /* PWParallaxScrollView-Info.plist */, 163 | F4E98C2818ECEF220078CB10 /* PWParallaxScrollView-Prefix.pch */, 164 | ); 165 | name = Resources; 166 | path = PWParallaxScrollViewExample; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXGroup section */ 170 | 171 | /* Begin PBXNativeTarget section */ 172 | F431D3901C65DE7E009F5851 /* PWParallaxScrollView_ObjCUseSwift */ = { 173 | isa = PBXNativeTarget; 174 | buildConfigurationList = F431D3A51C65DE7F009F5851 /* Build configuration list for PBXNativeTarget "PWParallaxScrollView_ObjCUseSwift" */; 175 | buildPhases = ( 176 | F431D38D1C65DE7E009F5851 /* Sources */, 177 | F431D38E1C65DE7E009F5851 /* Frameworks */, 178 | F431D38F1C65DE7E009F5851 /* Resources */, 179 | ); 180 | buildRules = ( 181 | ); 182 | dependencies = ( 183 | ); 184 | name = PWParallaxScrollView_ObjCUseSwift; 185 | productName = PWParallaxScrollView_ObjCUseSwift; 186 | productReference = F431D3911C65DE7E009F5851 /* PWParallaxScrollView_ObjCUseSwift.app */; 187 | productType = "com.apple.product-type.application"; 188 | }; 189 | F497D91817DC93EF007DE2EC /* PWParallaxScrollView */ = { 190 | isa = PBXNativeTarget; 191 | buildConfigurationList = F497D93F17DC93F0007DE2EC /* Build configuration list for PBXNativeTarget "PWParallaxScrollView" */; 192 | buildPhases = ( 193 | F497D91517DC93EF007DE2EC /* Sources */, 194 | F497D91617DC93EF007DE2EC /* Frameworks */, 195 | F497D91717DC93EF007DE2EC /* Resources */, 196 | ); 197 | buildRules = ( 198 | ); 199 | dependencies = ( 200 | ); 201 | name = PWParallaxScrollView; 202 | productName = PWParallaxScrollView; 203 | productReference = F497D91917DC93EF007DE2EC /* PWParallaxScrollView.app */; 204 | productType = "com.apple.product-type.application"; 205 | }; 206 | /* End PBXNativeTarget section */ 207 | 208 | /* Begin PBXProject section */ 209 | F497D91117DC93EF007DE2EC /* Project object */ = { 210 | isa = PBXProject; 211 | attributes = { 212 | LastSwiftUpdateCheck = 0730; 213 | LastUpgradeCheck = 0730; 214 | ORGANIZATIONNAME = Prince; 215 | TargetAttributes = { 216 | F431D3901C65DE7E009F5851 = { 217 | CreatedOnToolsVersion = 7.3; 218 | }; 219 | }; 220 | }; 221 | buildConfigurationList = F497D91417DC93EF007DE2EC /* Build configuration list for PBXProject "PWParallaxScrollView" */; 222 | compatibilityVersion = "Xcode 3.2"; 223 | developmentRegion = English; 224 | hasScannedForEncodings = 0; 225 | knownRegions = ( 226 | en, 227 | Base, 228 | ); 229 | mainGroup = F497D91017DC93EF007DE2EC; 230 | productRefGroup = F497D91A17DC93EF007DE2EC /* Products */; 231 | projectDirPath = ""; 232 | projectRoot = ""; 233 | targets = ( 234 | F497D91817DC93EF007DE2EC /* PWParallaxScrollView */, 235 | F431D3901C65DE7E009F5851 /* PWParallaxScrollView_ObjCUseSwift */, 236 | ); 237 | }; 238 | /* End PBXProject section */ 239 | 240 | /* Begin PBXResourcesBuildPhase section */ 241 | F431D38F1C65DE7E009F5851 /* Resources */ = { 242 | isa = PBXResourcesBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | F431D3C01C65E532009F5851 /* LaunchScreen.storyboard in Resources */, 246 | F431D3BB1C65E44D009F5851 /* 4.jpg in Resources */, 247 | F431D3BA1C65E44D009F5851 /* 3.jpg in Resources */, 248 | F431D3BD1C65E44D009F5851 /* 6.jpg in Resources */, 249 | F431D3B81C65E44D009F5851 /* 1.jpg in Resources */, 250 | F431D3BC1C65E44D009F5851 /* 5.jpg in Resources */, 251 | F431D3B91C65E44D009F5851 /* 2.jpg in Resources */, 252 | F431D3B51C65E2A9009F5851 /* ViewController.xib in Resources */, 253 | ); 254 | runOnlyForDeploymentPostprocessing = 0; 255 | }; 256 | F497D91717DC93EF007DE2EC /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | F4E98C4718ECEFA50078CB10 /* 6.jpg in Resources */, 261 | F4E98C4618ECEFA50078CB10 /* 5.jpg in Resources */, 262 | F4E98C4518ECEFA50078CB10 /* 4.jpg in Resources */, 263 | F4E98C4418ECEFA50078CB10 /* 3.jpg in Resources */, 264 | F431D3BF1C65E532009F5851 /* LaunchScreen.storyboard in Resources */, 265 | F4E98C3518ECEF220078CB10 /* InfoPlist.strings in Resources */, 266 | F4E98C4318ECEFA50078CB10 /* 2.jpg in Resources */, 267 | F4E98C3718ECEF220078CB10 /* ViewController.xib in Resources */, 268 | F4E98C4218ECEFA50078CB10 /* 1.jpg in Resources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | /* End PBXResourcesBuildPhase section */ 273 | 274 | /* Begin PBXSourcesBuildPhase section */ 275 | F431D38D1C65DE7E009F5851 /* Sources */ = { 276 | isa = PBXSourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | F431D3B71C65E3D4009F5851 /* main.m in Sources */, 280 | F431D3B31C65E175009F5851 /* PWParallaxScrollView.swift in Sources */, 281 | F47F3C581C65FAEF0042CF2E /* ViewController.m in Sources */, 282 | F431D3B61C65E3A2009F5851 /* AppDelegate.m in Sources */, 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | }; 286 | F497D91517DC93EF007DE2EC /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | F4E98C3118ECEF220078CB10 /* AppDelegate.m in Sources */, 291 | F4E98C3818ECEF220078CB10 /* main.m in Sources */, 292 | F4E98C3A18ECEF220078CB10 /* ViewController.m in Sources */, 293 | F4E98C1318ECEE450078CB10 /* PWParallaxScrollView.m in Sources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | /* End PBXSourcesBuildPhase section */ 298 | 299 | /* Begin PBXVariantGroup section */ 300 | F4E98C2018ECEF220078CB10 /* InfoPlist.strings */ = { 301 | isa = PBXVariantGroup; 302 | children = ( 303 | F4E98C2118ECEF220078CB10 /* en */, 304 | ); 305 | name = InfoPlist.strings; 306 | sourceTree = ""; 307 | }; 308 | F4E98C2418ECEF220078CB10 /* ViewController.xib */ = { 309 | isa = PBXVariantGroup; 310 | children = ( 311 | F4E98C2518ECEF220078CB10 /* en */, 312 | ); 313 | name = ViewController.xib; 314 | sourceTree = ""; 315 | }; 316 | /* End PBXVariantGroup section */ 317 | 318 | /* Begin XCBuildConfiguration section */ 319 | F431D3A61C65DE7F009F5851 /* Debug */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 326 | CLANG_WARN_UNREACHABLE_CODE = YES; 327 | DEBUG_INFORMATION_FORMAT = dwarf; 328 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 329 | ENABLE_STRICT_OBJC_MSGSEND = YES; 330 | ENABLE_TESTABILITY = YES; 331 | GCC_NO_COMMON_BLOCKS = YES; 332 | GCC_PREPROCESSOR_DEFINITIONS = ( 333 | "DEBUG=1", 334 | OBJC_USE_SWIFT_DEMO, 335 | ); 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | INFOPLIST_FILE = "PWParallaxScrollViewExample/PWParallaxScrollView-Info.plist"; 342 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 343 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 344 | MTL_ENABLE_DEBUG_INFO = YES; 345 | PRODUCT_BUNDLE_IDENTIFIER = "com.wpsteak.objcuseswift.PWParallaxScrollView-ObjCUseSwift"; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | SWIFT_OBJC_BRIDGING_HEADER = "PWParallaxScrollViewExample/PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h"; 348 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 349 | }; 350 | name = Debug; 351 | }; 352 | F431D3A71C65DE7F009F5851 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 358 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 359 | CLANG_WARN_UNREACHABLE_CODE = YES; 360 | COPY_PHASE_STRIP = NO; 361 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 362 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 363 | ENABLE_NS_ASSERTIONS = NO; 364 | ENABLE_STRICT_OBJC_MSGSEND = YES; 365 | GCC_NO_COMMON_BLOCKS = YES; 366 | GCC_PREPROCESSOR_DEFINITIONS = OBJC_USE_SWIFT_DEMO; 367 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 368 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 369 | GCC_WARN_UNDECLARED_SELECTOR = YES; 370 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 371 | GCC_WARN_UNUSED_FUNCTION = YES; 372 | INFOPLIST_FILE = "PWParallaxScrollViewExample/PWParallaxScrollView-Info.plist"; 373 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 375 | MTL_ENABLE_DEBUG_INFO = NO; 376 | PRODUCT_BUNDLE_IDENTIFIER = "com.wpsteak.objcuseswift.PWParallaxScrollView-ObjCUseSwift"; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | SWIFT_OBJC_BRIDGING_HEADER = "PWParallaxScrollViewExample/PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h"; 379 | }; 380 | name = Release; 381 | }; 382 | F497D93D17DC93F0007DE2EC /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ALWAYS_SEARCH_USER_PATHS = NO; 386 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 387 | CLANG_CXX_LIBRARY = "libc++"; 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | CLANG_WARN_CONSTANT_CONVERSION = YES; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INT_CONVERSION = YES; 393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 395 | COPY_PHASE_STRIP = NO; 396 | ENABLE_TESTABILITY = YES; 397 | GCC_C_LANGUAGE_STANDARD = gnu99; 398 | GCC_DYNAMIC_NO_PIC = NO; 399 | GCC_OPTIMIZATION_LEVEL = 0; 400 | GCC_PREPROCESSOR_DEFINITIONS = ( 401 | "DEBUG=1", 402 | "$(inherited)", 403 | ); 404 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 409 | ONLY_ACTIVE_ARCH = YES; 410 | SDKROOT = iphoneos; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | }; 413 | name = Debug; 414 | }; 415 | F497D93E17DC93F0007DE2EC /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | ALWAYS_SEARCH_USER_PATHS = NO; 419 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 420 | CLANG_CXX_LIBRARY = "libc++"; 421 | CLANG_ENABLE_OBJC_ARC = YES; 422 | CLANG_WARN_CONSTANT_CONVERSION = YES; 423 | CLANG_WARN_EMPTY_BODY = YES; 424 | CLANG_WARN_ENUM_CONVERSION = YES; 425 | CLANG_WARN_INT_CONVERSION = YES; 426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 427 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 428 | COPY_PHASE_STRIP = YES; 429 | GCC_C_LANGUAGE_STANDARD = gnu99; 430 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 432 | GCC_WARN_UNUSED_VARIABLE = YES; 433 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 434 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 435 | SDKROOT = iphoneos; 436 | TARGETED_DEVICE_FAMILY = "1,2"; 437 | VALIDATE_PRODUCT = YES; 438 | }; 439 | name = Release; 440 | }; 441 | F497D94017DC93F0007DE2EC /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 445 | GCC_PREFIX_HEADER = "PWParallaxScrollViewExample/PWParallaxScrollView-Prefix.pch"; 446 | HEADER_SEARCH_PATHS = ( 447 | "$(inherited)", 448 | "\"$(SRCROOT)/** /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", 449 | ); 450 | INFOPLIST_FILE = "PWParallaxScrollViewExample/PWParallaxScrollView-Info.plist"; 451 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 452 | PRODUCT_BUNDLE_IDENTIFIER = "wpsteak.${PRODUCT_NAME:rfc1034identifier}"; 453 | PRODUCT_NAME = "$(TARGET_NAME)"; 454 | WRAPPER_EXTENSION = app; 455 | }; 456 | name = Debug; 457 | }; 458 | F497D94117DC93F0007DE2EC /* Release */ = { 459 | isa = XCBuildConfiguration; 460 | buildSettings = { 461 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 462 | GCC_PREFIX_HEADER = "PWParallaxScrollViewExample/PWParallaxScrollView-Prefix.pch"; 463 | HEADER_SEARCH_PATHS = ( 464 | "$(inherited)", 465 | "\"$(SRCROOT)/** /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include", 466 | ); 467 | INFOPLIST_FILE = "PWParallaxScrollViewExample/PWParallaxScrollView-Info.plist"; 468 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 469 | PRODUCT_BUNDLE_IDENTIFIER = "wpsteak.${PRODUCT_NAME:rfc1034identifier}"; 470 | PRODUCT_NAME = "$(TARGET_NAME)"; 471 | WRAPPER_EXTENSION = app; 472 | }; 473 | name = Release; 474 | }; 475 | /* End XCBuildConfiguration section */ 476 | 477 | /* Begin XCConfigurationList section */ 478 | F431D3A51C65DE7F009F5851 /* Build configuration list for PBXNativeTarget "PWParallaxScrollView_ObjCUseSwift" */ = { 479 | isa = XCConfigurationList; 480 | buildConfigurations = ( 481 | F431D3A61C65DE7F009F5851 /* Debug */, 482 | F431D3A71C65DE7F009F5851 /* Release */, 483 | ); 484 | defaultConfigurationIsVisible = 0; 485 | defaultConfigurationName = Release; 486 | }; 487 | F497D91417DC93EF007DE2EC /* Build configuration list for PBXProject "PWParallaxScrollView" */ = { 488 | isa = XCConfigurationList; 489 | buildConfigurations = ( 490 | F497D93D17DC93F0007DE2EC /* Debug */, 491 | F497D93E17DC93F0007DE2EC /* Release */, 492 | ); 493 | defaultConfigurationIsVisible = 0; 494 | defaultConfigurationName = Release; 495 | }; 496 | F497D93F17DC93F0007DE2EC /* Build configuration list for PBXNativeTarget "PWParallaxScrollView" */ = { 497 | isa = XCConfigurationList; 498 | buildConfigurations = ( 499 | F497D94017DC93F0007DE2EC /* Debug */, 500 | F497D94117DC93F0007DE2EC /* Release */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | /* End XCConfigurationList section */ 506 | }; 507 | rootObject = F497D91117DC93EF007DE2EC /* Project object */; 508 | } 509 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/project.xcworkspace/xcshareddata/PWParallaxScrollView.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | CC0A0AFE-2449-4DAA-982F-77120E630008 9 | IDESourceControlProjectName 10 | PWParallaxScrollView 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 0D02EFF2-E474-4994-9FFA-5E26408D6717 14 | https://github.com/wpsteak/PWParallaxScrollView.git 15 | 16 | IDESourceControlProjectPath 17 | PWParallaxScrollView.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 0D02EFF2-E474-4994-9FFA-5E26408D6717 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/wpsteak/PWParallaxScrollView.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 0D02EFF2-E474-4994-9FFA-5E26408D6717 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 0D02EFF2-E474-4994-9FFA-5E26408D6717 36 | IDESourceControlWCCName 37 | PWParallaxScrollView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/project.xcworkspace/xcuserdata/wpsteak.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollView.xcodeproj/project.xcworkspace/xcuserdata/wpsteak.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/xcuserdata/wpsteak.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/xcuserdata/wpsteak.xcuserdatad/xcschemes/PWParallaxScrollView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 76 | 82 | 83 | 84 | 85 | 87 | 88 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/xcuserdata/wpsteak.xcuserdatad/xcschemes/PWParallaxScrollView_ObjCUseSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 76 | 82 | 83 | 84 | 85 | 87 | 88 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /PWParallaxScrollView.xcodeproj/xcuserdata/wpsteak.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PWParallaxScrollView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | PWParallaxScrollView_ObjCUseSwift.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | F431D36F1C65DE07009F5851 21 | 22 | primary 23 | 24 | 25 | F431D3901C65DE7E009F5851 26 | 27 | primary 28 | 29 | 30 | F497D91817DC93EF007DE2EC 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /PWParallaxScrollView/PWParallaxScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSParallaxScrollView.h 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/6/16. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol PWParallaxScrollViewDataSource; 12 | @protocol PWParallaxScrollViewDelegate; 13 | 14 | @interface PWParallaxScrollView : UIView 15 | 16 | @property (nonatomic, assign) IBOutlet id delegate; 17 | @property (nonatomic, assign) IBOutlet id dataSource; 18 | @property (nonatomic, readonly) NSInteger currentIndex; 19 | @property (nonatomic, assign) UIEdgeInsets foregroundScreenEdgeInsets; 20 | 21 | @property (nonatomic, assign) NSInteger maxAllowableItem; 22 | 23 | - (void)prevItem; 24 | - (void)nextItem; 25 | - (void)moveToIndex:(NSInteger)index; 26 | - (void)reloadData; 27 | 28 | @end 29 | 30 | @protocol PWParallaxScrollViewDataSource 31 | @required 32 | - (NSInteger)numberOfItemsInScrollView:(PWParallaxScrollView *)scrollView; 33 | 34 | @optional 35 | - (UIView *)backgroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView; 36 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView; 37 | 38 | @end 39 | 40 | @protocol PWParallaxScrollViewDelegate 41 | 42 | @optional 43 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didChangeIndex:(NSInteger)index; 44 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didEndDeceleratingAtIndex:(NSInteger)index; 45 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didRecieveTapAtIndex:(NSInteger)index; 46 | 47 | @end 48 | 49 | 50 | -------------------------------------------------------------------------------- /PWParallaxScrollView/PWParallaxScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PWParallaxScrollView.m 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/6/16. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import "PWParallaxScrollView.h" 10 | 11 | static const NSInteger PWInvalidPosition = -1; 12 | 13 | @interface PWParallaxScrollView () 14 | 15 | @property (nonatomic, assign) NSInteger numberOfItems; 16 | @property (nonatomic, assign) NSInteger backgroundViewIndex; 17 | @property (nonatomic, assign) NSInteger userHoldingDownIndex; 18 | 19 | @property (nonatomic, strong) UIScrollView *touchScrollView; 20 | @property (nonatomic, strong) UIScrollView *foregroundScrollView; 21 | @property (nonatomic, strong) UIScrollView *backgroundScrollView; 22 | 23 | @property (nonatomic, strong) UIView *currentBottomView; 24 | 25 | @property (nonatomic, assign) NSInteger currentIndex; 26 | 27 | - (void)touchScrollViewTapped:(id)sender; 28 | 29 | @end 30 | 31 | @implementation PWParallaxScrollView 32 | 33 | #pragma mark 34 | 35 | - (id)initWithCoder:(NSCoder *)aDecoder 36 | { 37 | self = [super initWithCoder:aDecoder]; 38 | if (self) { 39 | [self initControl]; 40 | } 41 | return self; 42 | } 43 | 44 | - (id)initWithFrame:(CGRect)frame 45 | { 46 | self = [super initWithFrame:frame]; 47 | if (self) { 48 | [self initControl]; 49 | } 50 | return self; 51 | } 52 | 53 | - (void)setDataSource:(id)dataSource 54 | { 55 | _dataSource = dataSource; 56 | [self reloadData]; 57 | } 58 | 59 | - (void)setForegroundScreenEdgeInsets:(UIEdgeInsets)foregroundScrollViewEdgeInsets 60 | { 61 | _foregroundScreenEdgeInsets = foregroundScrollViewEdgeInsets; 62 | [_foregroundScrollView setFrame:UIEdgeInsetsInsetRect(self.bounds, _foregroundScreenEdgeInsets)]; 63 | } 64 | 65 | - (void)initControl 66 | { 67 | self.backgroundColor = [UIColor blackColor]; 68 | self.clipsToBounds = YES; 69 | 70 | self.touchScrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 71 | _touchScrollView.delegate = self; 72 | _touchScrollView.pagingEnabled = YES; 73 | _touchScrollView.backgroundColor = [UIColor clearColor]; 74 | _touchScrollView.contentOffset = CGPointMake(0, 0); 75 | _touchScrollView.multipleTouchEnabled = YES; 76 | 77 | UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(touchScrollViewTapped:)]; 78 | tapGestureRecognize.numberOfTapsRequired = 1; 79 | [_touchScrollView addGestureRecognizer:tapGestureRecognize]; 80 | 81 | self.foregroundScrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 82 | _foregroundScrollView.scrollEnabled = NO; 83 | _foregroundScrollView.clipsToBounds = NO; 84 | _foregroundScrollView.backgroundColor = [UIColor clearColor]; 85 | _foregroundScrollView.contentOffset = CGPointMake(0, 0); 86 | 87 | self.backgroundScrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; 88 | _backgroundScrollView.pagingEnabled = YES; 89 | _backgroundScrollView.backgroundColor = [UIColor clearColor]; 90 | _backgroundScrollView.contentOffset = CGPointMake(0, 0); 91 | 92 | [self addSubview:_backgroundScrollView]; 93 | [self addSubview:_foregroundScrollView]; 94 | [self addSubview:_touchScrollView]; 95 | } 96 | 97 | #pragma mark - public method 98 | 99 | - (void)moveToIndex:(NSInteger)index 100 | { 101 | CGFloat newOffsetX = index * CGRectGetWidth(_touchScrollView.frame); 102 | [_touchScrollView scrollRectToVisible:CGRectMake(newOffsetX, 0, CGRectGetWidth(_touchScrollView.frame), CGRectGetHeight(_touchScrollView.frame)) animated:YES]; 103 | } 104 | 105 | - (void)prevItem 106 | { 107 | if (self.currentIndex > 0) { 108 | [self moveToIndex:self.currentIndex - 1]; 109 | } 110 | } 111 | 112 | - (void)nextItem 113 | { 114 | if (self.currentIndex < _numberOfItems - 1) { 115 | [self moveToIndex:self.currentIndex + 1]; 116 | } 117 | } 118 | 119 | - (void)reloadData 120 | { 121 | self.backgroundViewIndex = 0; 122 | self.userHoldingDownIndex = 0; 123 | self.numberOfItems = [self.dataSource numberOfItemsInScrollView:self]; 124 | 125 | UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame) * _numberOfItems, CGRectGetHeight(self.frame))]; 126 | contentView.backgroundColor = [UIColor clearColor]; 127 | 128 | [_backgroundScrollView setContentOffset:CGPointMake(0, 0) animated:NO]; 129 | [_backgroundScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 130 | [_backgroundScrollView addSubview:contentView]; 131 | [_backgroundScrollView setContentSize:contentView.frame.size]; 132 | 133 | [_foregroundScrollView setContentOffset:CGPointMake(0, 0) animated:NO]; 134 | [_foregroundScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 135 | [_foregroundScrollView setContentSize:CGSizeMake(CGRectGetWidth(_foregroundScrollView.frame) * _numberOfItems, CGRectGetHeight(_foregroundScrollView.frame))]; 136 | 137 | [_touchScrollView setContentOffset:CGPointMake(0, 0) animated:NO]; 138 | [_touchScrollView setContentSize:contentView.frame.size]; 139 | 140 | [self loadBackgroundViewAtIndex:0]; 141 | 142 | for (NSInteger i = 0; i < _numberOfItems; i++) { 143 | [self loadForegroundViewAtIndex:i]; 144 | } 145 | } 146 | 147 | #pragma mark - private method 148 | - (void)touchScrollViewTapped:(id)sender 149 | { 150 | if ([self.delegate respondsToSelector:@selector(parallaxScrollView:didRecieveTapAtIndex:)]) { 151 | [self.delegate parallaxScrollView:self didRecieveTapAtIndex:self.currentIndex]; 152 | } 153 | } 154 | 155 | - (UIView *)foregroundViewAtIndex:(NSInteger)index 156 | { 157 | if (index < 0 || index >= _numberOfItems) { 158 | return nil; 159 | } 160 | 161 | if (![self.dataSource respondsToSelector:@selector(foregroundViewAtIndex:scrollView:)]) { 162 | return nil; 163 | } 164 | 165 | UIView *view = [self.dataSource foregroundViewAtIndex:index scrollView:self]; 166 | CGRect newFrame = view.frame; 167 | newFrame.origin.x += index * CGRectGetWidth(_foregroundScrollView.frame); 168 | [view setFrame:newFrame]; 169 | [view setTag:index]; 170 | 171 | return view; 172 | } 173 | 174 | - (UIView *)backgroundViewAtIndex:(NSInteger)index 175 | { 176 | if (index < 0 || index >= _numberOfItems) { 177 | return nil; 178 | } 179 | 180 | UIView *view = [self.dataSource backgroundViewAtIndex:index scrollView:self]; 181 | [view setFrame:CGRectMake(index * CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))]; 182 | [view setTag:index]; 183 | 184 | return view; 185 | } 186 | 187 | - (void)loadForegroundViewAtIndex:(NSInteger)index 188 | { 189 | UIView *newParallaxView = [self foregroundViewAtIndex:index]; 190 | 191 | [_foregroundScrollView addSubview:newParallaxView]; 192 | } 193 | 194 | - (void)loadBackgroundViewAtIndex:(NSInteger)index 195 | { 196 | [[_backgroundScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 197 | 198 | UIView *newTopView = [self backgroundViewAtIndex:index]; 199 | [_backgroundScrollView addSubview:newTopView]; 200 | } 201 | 202 | - (void)determineBackgroundView:(float)offsetX 203 | { 204 | CGFloat newCenterX = 0; 205 | NSInteger newBackgroundViewIndex = 0; 206 | NSInteger midPoint = CGRectGetWidth(self.frame) * _userHoldingDownIndex; 207 | 208 | if (offsetX < midPoint) { 209 | //moving from left to right 210 | 211 | newCenterX = (CGRectGetWidth(self.frame) * _userHoldingDownIndex - offsetX) / 2; 212 | newBackgroundViewIndex = _userHoldingDownIndex - 1; 213 | } 214 | else if (offsetX > midPoint) { 215 | //moving from right to left 216 | 217 | CGFloat leftSplitWidth = CGRectGetWidth(self.frame) * (_userHoldingDownIndex + 1) - offsetX; 218 | CGFloat rightSplitWidth = CGRectGetWidth(self.frame) - leftSplitWidth; 219 | 220 | newCenterX = rightSplitWidth / 2 + leftSplitWidth; 221 | newBackgroundViewIndex = _userHoldingDownIndex + 1; 222 | } 223 | else { 224 | newCenterX = CGRectGetWidth(self.frame) / 2 ; 225 | newBackgroundViewIndex = _backgroundViewIndex; 226 | } 227 | 228 | BOOL backgroundViewIndexChanged = (newBackgroundViewIndex == _backgroundViewIndex) ? NO : YES; 229 | self.backgroundViewIndex = newBackgroundViewIndex; 230 | 231 | if (_userHoldingDownIndex >= 0 && _userHoldingDownIndex <= _numberOfItems) { 232 | if (backgroundViewIndexChanged) { 233 | [_currentBottomView removeFromSuperview]; 234 | self.currentBottomView = nil; 235 | 236 | UIView *newBottomView = [self backgroundViewAtIndex:_backgroundViewIndex]; 237 | self.currentBottomView = newBottomView; 238 | [self insertSubview:self.currentBottomView atIndex:0]; 239 | } 240 | } 241 | 242 | CGPoint center = CGPointMake(newCenterX, CGRectGetHeight(self.frame) / 2); 243 | self.currentBottomView.center = center; 244 | } 245 | 246 | - (NSInteger)backgroundViewIndexFromOffset:(CGPoint)offset 247 | { 248 | NSInteger index = (offset.x / CGRectGetWidth(self.frame)); 249 | 250 | if (index >= _numberOfItems || index < 0) { 251 | index = PWInvalidPosition; 252 | } 253 | 254 | return index; 255 | } 256 | 257 | #pragma mark UIScrollViewDelegate 258 | 259 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 260 | { 261 | [_backgroundScrollView setContentOffset:scrollView.contentOffset]; 262 | 263 | CGFloat factor = _foregroundScrollView.contentSize.width / scrollView.contentSize.width; 264 | [_foregroundScrollView setContentOffset:CGPointMake(factor * scrollView.contentOffset.x, 0)]; 265 | 266 | CGFloat offsetX = scrollView.contentOffset.x; 267 | [self determineBackgroundView:offsetX]; 268 | 269 | CGRect visibleRect; 270 | visibleRect.origin = scrollView.contentOffset; 271 | visibleRect.size = scrollView.bounds.size; 272 | 273 | CGRect userPenRect; 274 | CGFloat width = CGRectGetWidth(scrollView.frame); 275 | userPenRect.origin = CGPointMake(width * self.userHoldingDownIndex, 0); 276 | userPenRect.size = scrollView.bounds.size; 277 | 278 | if (!CGRectIntersectsRect(visibleRect, userPenRect)) { 279 | if (CGRectGetMinX(visibleRect) - CGRectGetMinX(userPenRect) > 0) { 280 | self.userHoldingDownIndex = _userHoldingDownIndex + 1; 281 | } 282 | else { 283 | self.userHoldingDownIndex = _userHoldingDownIndex - 1; 284 | } 285 | 286 | [self loadBackgroundViewAtIndex:_userHoldingDownIndex]; 287 | } 288 | 289 | CGFloat newCrrentIndex = round(1.0f * scrollView.contentOffset.x / CGRectGetWidth(self.frame)); 290 | 291 | if(_currentIndex != newCrrentIndex) { 292 | self.currentIndex = newCrrentIndex; 293 | 294 | if([self.delegate respondsToSelector:@selector(parallaxScrollView:didChangeIndex:)]){ 295 | [self.delegate parallaxScrollView:self didChangeIndex:self.currentIndex]; 296 | } 297 | } 298 | } 299 | 300 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 301 | { 302 | if([self.delegate respondsToSelector:@selector(parallaxScrollView:didEndDeceleratingAtIndex:)]){ 303 | [self.delegate parallaxScrollView:self didEndDeceleratingAtIndex:self.currentIndex]; 304 | } 305 | } 306 | 307 | #pragma mark hitTest 308 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 309 | { 310 | for (UIView *subview in _foregroundScrollView.subviews) { 311 | CGPoint convertedPoint = [self convertPoint:point toView:subview]; 312 | UIView *result = [subview hitTest:convertedPoint withEvent:event]; 313 | 314 | if ([result isKindOfClass:[UIButton class]]){ 315 | return result; 316 | } 317 | } 318 | 319 | return [super hitTest:point withEvent:event]; 320 | } 321 | 322 | @end 323 | -------------------------------------------------------------------------------- /PWParallaxScrollView/PWParallaxScrollView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PWParallaxScrollView.swift 3 | // PWParallaxScrollView-Swift 4 | // 5 | // Created by wpsteak on 12/15/15. 6 | // Copyright © 2015 Pin Shih Wang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private let PWInvalidPosition :Int = -1 12 | 13 | @objc 14 | public protocol PWParallaxScrollViewDataSource : NSObjectProtocol { 15 | func numberOfItemsInScrollView(scrollView: PWParallaxScrollView) -> Int 16 | 17 | optional func backgroundViewAtIndex(index: Int, scrollView: PWParallaxScrollView) -> UIView? 18 | optional func foregroundViewAtIndex(index: Int, scrollView: PWParallaxScrollView) -> UIView? 19 | } 20 | 21 | 22 | @objc 23 | public protocol PWParallaxScrollViewDelegate : NSObjectProtocol { 24 | 25 | optional func parallaxScrollView(scrollView: PWParallaxScrollView, didChangeIndex index: Int) 26 | optional func parallaxScrollView(scrollView: PWParallaxScrollView, didEndDeceleratingAtIndex index: Int) 27 | optional func parallaxScrollView(scrollView: PWParallaxScrollView, didRecieveTapAtIndex index: Int) 28 | } 29 | 30 | @objc 31 | public class PWParallaxScrollView: UIView, UIScrollViewDelegate { 32 | weak public var dataSource: PWParallaxScrollViewDataSource? { 33 | didSet { 34 | reloadData() 35 | } 36 | } 37 | weak public var delegate: PWParallaxScrollViewDelegate? 38 | 39 | public var foregroundScreenEdgeInsets: UIEdgeInsets = UIEdgeInsetsZero { 40 | didSet { 41 | foregroundScrollView.frame = UIEdgeInsetsInsetRect(self.bounds, foregroundScreenEdgeInsets) 42 | } 43 | } 44 | 45 | private var touchScrollView: UIScrollView = UIScrollView() 46 | private var foregroundScrollView: UIScrollView = UIScrollView() 47 | private var backgroundScrollView: UIScrollView = UIScrollView() 48 | 49 | private var currentBottomView: UIView? 50 | 51 | private var numberOfItems: Int = 0 52 | private var backgroundViewIndex: Int = 0 53 | private var userHoldingDownIndex: Int = 0 54 | 55 | private var currentIndex: Int = 0 56 | 57 | private func setup() { 58 | self.backgroundColor = UIColor.blackColor() 59 | self.clipsToBounds = true; 60 | 61 | touchScrollView.frame = self.bounds 62 | touchScrollView.pagingEnabled = true 63 | touchScrollView.backgroundColor = UIColor.clearColor() 64 | touchScrollView.contentOffset = CGPointMake(0, 0) 65 | touchScrollView.multipleTouchEnabled = true 66 | touchScrollView.delegate = self 67 | 68 | foregroundScrollView.scrollEnabled = false 69 | foregroundScrollView.clipsToBounds = false 70 | foregroundScrollView.backgroundColor = UIColor.clearColor() 71 | foregroundScrollView.contentOffset = CGPointMake(0, 0); 72 | 73 | backgroundScrollView.frame = self.bounds 74 | backgroundScrollView.pagingEnabled = true 75 | backgroundScrollView.backgroundColor = UIColor.clearColor() 76 | backgroundScrollView.contentOffset = CGPointMake(0, 0) 77 | 78 | self.addSubview(backgroundScrollView) 79 | self.addSubview(foregroundScrollView) 80 | self.addSubview(touchScrollView) 81 | } 82 | 83 | override public init(frame: CGRect) { 84 | super.init(frame: frame) 85 | setup() 86 | } 87 | 88 | required public init?(coder aDecoder: NSCoder) { 89 | super.init(coder: aDecoder) 90 | setup() 91 | } 92 | 93 | public func reloadData() { 94 | backgroundViewIndex = 0 95 | userHoldingDownIndex = 0 96 | numberOfItems = self.dataSource?.numberOfItemsInScrollView(self) ?? 0 97 | 98 | 99 | let contentView: UIView = UIView(frame: CGRectMake(0, 0, CGRectGetWidth(self.frame) * CGFloat(numberOfItems), CGRectGetHeight(self.frame))) 100 | contentView.backgroundColor = UIColor.clearColor() 101 | 102 | backgroundScrollView.setContentOffset(CGPointMake(0, 0), animated: false) 103 | backgroundScrollView.subviews.forEach { subview in 104 | subview.removeFromSuperview() 105 | } 106 | backgroundScrollView.addSubview(contentView) 107 | backgroundScrollView.contentSize = contentView.frame.size 108 | 109 | foregroundScrollView.setContentOffset(CGPointMake(0, 0), animated: false) 110 | foregroundScrollView.subviews.forEach { subview in 111 | subview.removeFromSuperview() 112 | } 113 | foregroundScrollView.contentSize = CGSizeMake(CGRectGetWidth(foregroundScrollView.frame) * CGFloat(numberOfItems), CGRectGetHeight(foregroundScrollView.frame)) 114 | 115 | touchScrollView.setContentOffset(CGPointMake(0, 0), animated: false) 116 | touchScrollView.contentSize = contentView.frame.size 117 | 118 | loadBackgroundViewAtIndex(0) 119 | 120 | for index in 0.. 0) { 133 | moveToIndex(self.currentIndex - 1) 134 | } 135 | } 136 | 137 | public func nextItem() { 138 | if (self.currentIndex < numberOfItems - 1) { 139 | moveToIndex(self.currentIndex + 1) 140 | } 141 | } 142 | 143 | private func loadForegroundViewAtIndex(index: Int) { 144 | if let newParallaxView: UIView = foregroundViewAtIndex(index) { 145 | foregroundScrollView.addSubview(newParallaxView) 146 | } 147 | } 148 | 149 | private func loadBackgroundViewAtIndex(index: Int) { 150 | backgroundScrollView.subviews.forEach { subview in 151 | subview.removeFromSuperview() 152 | } 153 | 154 | if let newTopView: UIView = backgroundViewAtIndex(index) { 155 | backgroundScrollView.addSubview(newTopView) 156 | } 157 | } 158 | 159 | private func foregroundViewAtIndex(index: Int) -> UIView? { 160 | 161 | if (index < 0 || index >= numberOfItems) { 162 | return nil 163 | } 164 | 165 | if let view: UIView = self.dataSource?.foregroundViewAtIndex?(index, scrollView: self) { 166 | var newFrame: CGRect = view.frame 167 | newFrame.origin.x += CGFloat(index) * CGRectGetWidth(foregroundScrollView.frame) 168 | view.frame = newFrame 169 | view.tag = index 170 | 171 | return view 172 | } 173 | else { 174 | return nil 175 | } 176 | } 177 | 178 | private func backgroundViewAtIndex(index: Int) -> UIView? { 179 | 180 | if (index < 0 || index >= numberOfItems) { 181 | return nil 182 | } 183 | 184 | let view: UIView? = self.dataSource?.backgroundViewAtIndex?(index, scrollView: self) 185 | 186 | view?.frame = CGRectMake((CGFloat)(index * Int(CGRectGetWidth(self.frame))), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) 187 | view?.tag = index 188 | 189 | return view 190 | } 191 | 192 | private func determineBackgroundView(offsetX: CGFloat) { 193 | var newCenterX: CGFloat = 0 194 | var newBackgroundViewIndex: Int = 0; 195 | let midPoint: CGFloat = CGRectGetWidth(self.frame) * CGFloat(userHoldingDownIndex); 196 | 197 | if (offsetX < midPoint) { 198 | //moving from left to right 199 | 200 | newCenterX = (CGRectGetWidth(self.frame) * CGFloat(userHoldingDownIndex) - offsetX) / 2; 201 | newBackgroundViewIndex = userHoldingDownIndex - 1; 202 | } 203 | else if (offsetX > midPoint) { 204 | //moving from right to left 205 | 206 | let leftSplitWidth: CGFloat = CGRectGetWidth(self.frame) * CGFloat(userHoldingDownIndex + 1) - offsetX; 207 | let rightSplitWidth: CGFloat = CGRectGetWidth(self.frame) - leftSplitWidth; 208 | 209 | newCenterX = rightSplitWidth / 2 + leftSplitWidth; 210 | newBackgroundViewIndex = userHoldingDownIndex + 1; 211 | } 212 | else { 213 | newCenterX = CGRectGetWidth(self.frame) / 2 ; 214 | newBackgroundViewIndex = backgroundViewIndex; 215 | } 216 | 217 | let backgroundViewIndexChanged: Bool = (newBackgroundViewIndex == backgroundViewIndex) ? false : true; 218 | backgroundViewIndex = newBackgroundViewIndex; 219 | 220 | if (userHoldingDownIndex >= 0 && userHoldingDownIndex <= numberOfItems) { 221 | if (backgroundViewIndexChanged) { 222 | currentBottomView?.removeFromSuperview() 223 | 224 | if let newBottomView: UIView = backgroundViewAtIndex(backgroundViewIndex) { 225 | currentBottomView = newBottomView; 226 | self.insertSubview(newBottomView, atIndex: 0) 227 | } 228 | } 229 | } 230 | 231 | let center: CGPoint = CGPointMake(newCenterX, CGRectGetHeight(self.frame) / 2); 232 | currentBottomView?.center = center; 233 | } 234 | 235 | private func backgroundViewIndexFromOffset(offset: CGPoint) -> Int { 236 | var index: Int = Int(offset.x / CGRectGetWidth(self.frame)) 237 | 238 | if (index >= numberOfItems || index < 0) { 239 | index = PWInvalidPosition; 240 | } 241 | 242 | return index; 243 | } 244 | 245 | // MARK: UIScrollViewDelegate 246 | 247 | public func scrollViewDidScroll(scrollView: UIScrollView) { 248 | backgroundScrollView.contentOffset = scrollView.contentOffset 249 | 250 | let factor = foregroundScrollView.contentSize.width / scrollView.contentSize.width 251 | foregroundScrollView.contentOffset = CGPointMake(factor * scrollView.contentOffset.x, 0) 252 | 253 | let offsetX = scrollView.contentOffset.x 254 | determineBackgroundView(offsetX) 255 | 256 | let visibleRect = CGRect(origin: scrollView.contentOffset, size: scrollView.bounds.size) 257 | 258 | let width: CGFloat = CGRectGetWidth(scrollView.frame); 259 | let userPenRect = CGRect(origin: CGPointMake(CGFloat(Int(width) * userHoldingDownIndex), 0), size: scrollView.bounds.size) 260 | 261 | if (!CGRectIntersectsRect(visibleRect, userPenRect)) { 262 | if (CGRectGetMinX(visibleRect) - CGRectGetMinX(userPenRect) > 0) { 263 | userHoldingDownIndex = userHoldingDownIndex + 1 264 | } 265 | else { 266 | userHoldingDownIndex = userHoldingDownIndex - 1 267 | } 268 | 269 | loadBackgroundViewAtIndex(userHoldingDownIndex) 270 | } 271 | 272 | let newCrrentIndex = Int(1.0 * scrollView.contentOffset.x / CGRectGetWidth(self.frame)); 273 | 274 | if(currentIndex != newCrrentIndex) { 275 | self.currentIndex = newCrrentIndex; 276 | 277 | self.delegate?.parallaxScrollView?(self, didChangeIndex: currentIndex) 278 | } 279 | } 280 | 281 | // MARK: hitTest 282 | 283 | public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 284 | for subview in foregroundScrollView.subviews { 285 | let convertedPoint = convertPoint(point, toView: subview) 286 | let result = subview.hitTest(convertedPoint, withEvent: event) 287 | 288 | if result is UIButton { 289 | return result 290 | } 291 | } 292 | 293 | return super.hitTest(point, withEvent: event) 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/9/8. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ViewController; 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) ViewController *viewController; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/9/8. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | @implementation AppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 18 | // Override point for customization after application launch. 19 | 20 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 21 | 22 | self.window.rootViewController = self.viewController; 23 | [self.window makeKeyAndVisible]; 24 | return YES; 25 | } 26 | 27 | - (void)applicationWillResignActive:(UIApplication *)application 28 | { 29 | // 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. 30 | // 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. 31 | } 32 | 33 | - (void)applicationDidEnterBackground:(UIApplication *)application 34 | { 35 | // 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. 36 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 37 | } 38 | 39 | - (void)applicationWillEnterForeground:(UIApplication *)application 40 | { 41 | // 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. 42 | } 43 | 44 | - (void)applicationDidBecomeActive:(UIApplication *)application 45 | { 46 | // 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. 47 | } 48 | 49 | - (void)applicationWillTerminate:(UIApplication *)application 50 | { 51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/1.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/2.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/3.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/4.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/5.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/Images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/PWParallaxScrollViewExample/Images/6.jpg -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/PWParallaxScrollView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationLandscapeLeft 36 | UIInterfaceOrientationLandscapeRight 37 | 38 | UISupportedInterfaceOrientations~ipad 39 | 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/PWParallaxScrollView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PWParallaxScrollView' target in the 'PWParallaxScrollView' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/PWParallaxScrollView_ObjCUseSwift-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/9/8. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/9/8. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #ifdef OBJC_USE_SWIFT_DEMO 12 | #import "PWParallaxScrollView_ObjCUseSwift-swift.h" 13 | #else 14 | #import "PWParallaxScrollView.h" 15 | #endif 16 | 17 | 18 | @interface ViewController () 19 | 20 | @property (nonatomic, strong) PWParallaxScrollView *scrollView; 21 | @property (nonatomic, strong) NSArray *photos; 22 | 23 | @property (nonatomic, weak) IBOutlet UIPageControl *pageControl; 24 | @end 25 | 26 | @implementation ViewController 27 | 28 | - (IBAction)prev:(id)sender 29 | { 30 | [_scrollView prevItem]; 31 | } 32 | 33 | - (IBAction)next:(id)sender 34 | { 35 | [_scrollView nextItem]; 36 | } 37 | 38 | - (IBAction)jumpToItem:(id)sender 39 | { 40 | [_scrollView moveToIndex:3]; 41 | } 42 | 43 | #pragma mark - PWParallaxScrollViewSource 44 | 45 | - (NSInteger)numberOfItemsInScrollView:(PWParallaxScrollView *)scrollView 46 | { 47 | self.pageControl.numberOfPages = [self.photos count]; 48 | return self.pageControl.numberOfPages; 49 | } 50 | 51 | - (UIView *)backgroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView 52 | { 53 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.photos[index]]]; 54 | imageView.contentMode = UIViewContentModeScaleAspectFill; 55 | return imageView; 56 | } 57 | 58 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView 59 | { 60 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 300, 70)]; 61 | [label setBackgroundColor:[UIColor blackColor]]; 62 | [label setTextColor:[UIColor whiteColor]]; 63 | [label setFont:[UIFont boldSystemFontOfSize:60.0f]]; 64 | [label setTextAlignment:NSTextAlignmentCenter]; 65 | [label setText:[NSString stringWithFormat:@"Title %@", @(index + 1)]]; 66 | [label setAlpha:0.7f]; 67 | [label setUserInteractionEnabled:YES]; 68 | 69 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 70 | [button setFrame:label.bounds]; 71 | [button setShowsTouchWhenHighlighted:YES]; 72 | [button addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside]; 73 | [label addSubview:button]; 74 | 75 | return label; 76 | } 77 | 78 | - (void)test 79 | { 80 | NSLog(@"hit test"); 81 | } 82 | 83 | #pragma mark - PWParallaxScrollViewDelegate 84 | 85 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didChangeIndex:(NSInteger)index 86 | { 87 | _pageControl.currentPage = index; 88 | } 89 | 90 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didEndDeceleratingAtIndex:(NSInteger)index 91 | { 92 | 93 | } 94 | 95 | #pragma mark - view's life cycle 96 | 97 | - (void)initControl 98 | { 99 | self.scrollView = [[PWParallaxScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds]; 100 | 101 | // _scrollView.foregroundScreenEdgeInsets = UIEdgeInsetsZero; 102 | _scrollView.foregroundScreenEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 100); 103 | [self.view insertSubview:_scrollView atIndex:0]; 104 | } 105 | 106 | - (void)setContent:(id)content 107 | { 108 | self.photos = @[@"1.jpg", @"2.jpg", @"3.jpg", @"4.jpg", @"5.jpg", @"6.jpg"]; 109 | } 110 | 111 | - (void)reloadData 112 | { 113 | _scrollView.delegate = self; 114 | _scrollView.dataSource = self; 115 | } 116 | 117 | - (void)viewDidLoad 118 | { 119 | [super viewDidLoad]; 120 | // Do any additional setup after loading the view, typically from a nib. 121 | 122 | [self initControl]; 123 | [self setContent:nil]; 124 | [self reloadData]; 125 | } 126 | 127 | - (void)didReceiveMemoryWarning 128 | { 129 | [super didReceiveMemoryWarning]; 130 | // Dispose of any resources that can be recreated. 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/en.lproj/ViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 34 | 50 | 51 | 52 | 53 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /PWParallaxScrollViewExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PWParallaxScrollView 4 | // 5 | // Created by wpsteak on 13/9/8. 6 | // Copyright (c) 2013年 wpsteak. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PWParallaxScrollView (ObjC / Swift) 2 | ==================== 3 | 4 | PWParallaxScrollView is a library for creating sliding menus with parallax effect inspired by the WWF app 5 | 6 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/screenshot.gif) 7 | 8 | 9 | ## CocoaPods 10 | 11 | for ObjC 12 | 13 | ``` 14 | pod 'PWParallaxScrollView', '~> 1.2.0' 15 | ``` 16 | 17 | for Swift, 18 | 19 | ``` 20 | pod 'PWParallaxScrollView/Swift', '~> 1.2.0' 21 | ``` 22 | 23 | 24 | ## Usage 25 | 26 | ##### import header 27 | 28 | ```objc 29 | #import "PWParallaxScrollView.h" 30 | ``` 31 | 32 | ##### follow PWParallaxScrollViewDataSource protocol 33 | 34 | ```objc 35 | @interface ViewController 36 | ``` 37 | 38 | ##### implement PWParallaxScrollViewDataSource methods 39 | 40 | ```objc 41 | - (NSInteger)numberOfItemsInScrollView:(PWParallaxScrollView *)scrollView; 42 | - (UIView *)backgroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView; 43 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView; 44 | 45 | ``` 46 | ##### setting ForegroundScreenEdgeInsets 47 | 48 | 49 | 50 | ## About ForegroundScreenEdgeInsets 51 | ### custom your parallax offset 52 | 53 | ##### foregroundScreenEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 100); 54 | 55 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/edgeinsets.gif) 56 | 57 | ##### sample code 58 | 59 | ```objc 60 | self.scrollView = [[PWParallaxScrollView alloc] initWithFrame:self.view.bounds]; 61 | _scrollView.foregroundScreenEdgeInsets = UIEdgeInsetsMake(0, 30, 0, 100); 62 | [self.view insertSubview:_scrollView atIndex:0]; 63 | 64 | ``` 65 | ```objc 66 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView 67 | { 68 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 300, 70)]; 69 | 70 | ... 71 | 72 | return label; 73 | } 74 | ``` 75 | ### Normal 76 | 77 | ##### foregroundScreenEdgeInsets = UIEdgeInsetsZero; 78 | 79 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/edgeinsets1.gif) 80 | 81 | ##### sample code 82 | 83 | ```objc 84 | self.scrollView = [[PWParallaxScrollView alloc] initWithFrame:self.view.bounds]; 85 | _scrollView.foregroundScreenEdgeInsets = UIEdgeInsetsZero; 86 | [self.view insertSubview:_scrollView atIndex:0]; 87 | 88 | ``` 89 | ```objc 90 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView 91 | { 92 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 300, 70)]; 93 | 94 | ... 95 | 96 | return label; 97 | } 98 | ``` 99 | 100 | ## hit test 101 | 102 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/screenshot1.gif) 103 | 104 | ```objc 105 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView 106 | { 107 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 300, 70)]; 108 | ... 109 | 110 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 111 | ... 112 | [button addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside]; 113 | ... 114 | [label addSubview:button]; 115 | 116 | return label; 117 | } 118 | ``` 119 | 120 | ## moveToIndex , prev , next 121 | 122 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/screenshot3.gif) 123 | ##### sample code 124 | 125 | ```objc 126 | [scrollView moveToIndex:3]; 127 | ``` 128 | 129 | ```objc 130 | [scrollView prevItem]; 131 | ``` 132 | 133 | ```objc 134 | [scrollView nextItem]; 135 | ``` 136 | 137 | ## background view only 138 | 139 | ![](https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/master/gif/screenshot4.gif) 140 | 141 | ##### just not implement the foregroundViewAtIndex:scrollView: method (or return nil) 142 | 143 | ```objc 144 | - (UIView *)foregroundViewAtIndex:(NSInteger)index scrollView:(PWParallaxScrollView *)scrollView; 145 | 146 | ``` 147 | 148 | ## Change Log 1.2.0 149 | 150 | - add swift version 151 | 152 | #### Thanks for contribution 153 | 154 | - @yume190 155 | 156 | ## Change Log 1.1.5 157 | 158 | add delegate to receive touchScrollViewTapped event 159 | 160 | ```objc 161 | - (void)parallaxScrollView:(PWParallaxScrollView *)scrollView didRecieveTapAtIndex:(NSInteger)index; 162 | ``` 163 | 164 | #### Thanks for contribution 165 | 166 | - @Morgan-Kennedy 167 | 168 | ## Change Log 1.1.0 169 | 170 | - add interface builder support (initWithCoder, Outlets) 171 | 172 | - add PWParallaxDelegate and provides methods to check whether the current index is changed 173 | 174 | #### Thanks for contribution 175 | 176 | - @matibot 177 | 178 | ## MIT License 179 | 180 | PWParallaxScrollView is released under the MIT License (see the License file) 181 | 182 | ## Contact 183 | 184 | Any suggestions or improvements? 185 | 186 | feel free to contact me 187 | 188 | wpsteak@gmail.com 189 | -------------------------------------------------------------------------------- /gif/edgeinsets.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/edgeinsets.gif -------------------------------------------------------------------------------- /gif/edgeinsets1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/edgeinsets1.gif -------------------------------------------------------------------------------- /gif/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/screenshot.gif -------------------------------------------------------------------------------- /gif/screenshot1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/screenshot1.gif -------------------------------------------------------------------------------- /gif/screenshot3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/screenshot3.gif -------------------------------------------------------------------------------- /gif/screenshot4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/gif/screenshot4.gif -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsteak/PWParallaxScrollView/f2296b9c8b1d4253e7841375a4bf757ea8015feb/screenshot.png --------------------------------------------------------------------------------