├── .gitignore ├── LICENSE ├── ParallaxScrolling.xcodeproj └── project.pbxproj ├── ParallaxScrolling ├── AppDelegate.h ├── AppDelegate.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── ParallaxFlowLayout.h ├── ParallaxFlowLayout.m ├── ParallaxLayoutAttributes.h ├── ParallaxLayoutAttributes.m ├── ParallaxPhotoCell.h ├── ParallaxPhotoCell.m ├── ParallaxScrolling-Info.plist ├── ParallaxScrolling-Prefix.pch ├── Photos │ ├── 01-mallorca.jpg │ ├── 02-fishing.jpg │ ├── 03-chili.jpg │ ├── 04-rice.jpg │ ├── 05-sweden.jpg │ ├── 06-magicforest.jpg │ ├── 07-bird.jpg │ ├── 08-iguana.jpg │ ├── 09-valley.jpg │ ├── 10-parrots.jpg │ ├── 11-lapaz.jpg │ ├── 12-villarrica.jpg │ ├── 13-lakevolcano.jpg │ ├── 14-denseforest.jpg │ ├── 15-glacier1.jpg │ ├── 16-glacier2.jpg │ ├── 17-torresdelpaine1.jpg │ ├── 18-torresdelpaine2.jpg │ ├── 19-cat.jpg │ ├── 20-berlinskyline.jpg │ ├── 21-potsdamerplatz.jpg │ ├── 22-milchbar.jpg │ ├── 23-berlinlights.jpg │ ├── 24-tvtower.jpg │ ├── 25-winter.jpg │ ├── 26-tree.jpg │ ├── 27-beach.jpg │ └── Photos.plist ├── PhotosCollectionViewController.h ├── PhotosCollectionViewController.m ├── en.lproj │ └── InfoPlist.strings └── main.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | Pods/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ole Begemann 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. -------------------------------------------------------------------------------- /ParallaxScrolling.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5DE357C61912843E005CD2F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DE357C51912843E005CD2F2 /* Foundation.framework */; }; 11 | 5DE357C81912843E005CD2F2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DE357C71912843E005CD2F2 /* CoreGraphics.framework */; }; 12 | 5DE357CA1912843E005CD2F2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DE357C91912843E005CD2F2 /* UIKit.framework */; }; 13 | 5DE357D01912843E005CD2F2 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5DE357CE1912843E005CD2F2 /* InfoPlist.strings */; }; 14 | 5DE357D21912843E005CD2F2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE357D11912843E005CD2F2 /* main.m */; }; 15 | 5DE357D61912843E005CD2F2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE357D51912843E005CD2F2 /* AppDelegate.m */; }; 16 | 5DE357D81912843E005CD2F2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5DE357D71912843E005CD2F2 /* Images.xcassets */; }; 17 | 5DE357F6191284A3005CD2F2 /* PhotosCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE357F5191284A3005CD2F2 /* PhotosCollectionViewController.m */; }; 18 | 5DE357F9191284B2005CD2F2 /* ParallaxFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE357F8191284B2005CD2F2 /* ParallaxFlowLayout.m */; }; 19 | 5DE357FC191284D0005CD2F2 /* ParallaxPhotoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE357FB191284CF005CD2F2 /* ParallaxPhotoCell.m */; }; 20 | 5DE3581A19128E87005CD2F2 /* 01-mallorca.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE357FF19128E87005CD2F2 /* 01-mallorca.jpg */; }; 21 | 5DE3581B19128E87005CD2F2 /* 02-fishing.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580019128E87005CD2F2 /* 02-fishing.jpg */; }; 22 | 5DE3581C19128E87005CD2F2 /* 03-chili.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580119128E87005CD2F2 /* 03-chili.jpg */; }; 23 | 5DE3581D19128E87005CD2F2 /* 04-rice.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580219128E87005CD2F2 /* 04-rice.jpg */; }; 24 | 5DE3581E19128E87005CD2F2 /* 05-sweden.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580319128E87005CD2F2 /* 05-sweden.jpg */; }; 25 | 5DE3581F19128E87005CD2F2 /* 06-magicforest.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580419128E87005CD2F2 /* 06-magicforest.jpg */; }; 26 | 5DE3582019128E87005CD2F2 /* 07-bird.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580519128E87005CD2F2 /* 07-bird.jpg */; }; 27 | 5DE3582119128E87005CD2F2 /* 08-iguana.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580619128E87005CD2F2 /* 08-iguana.jpg */; }; 28 | 5DE3582219128E87005CD2F2 /* 09-valley.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580719128E87005CD2F2 /* 09-valley.jpg */; }; 29 | 5DE3582319128E87005CD2F2 /* 10-parrots.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580819128E87005CD2F2 /* 10-parrots.jpg */; }; 30 | 5DE3582419128E87005CD2F2 /* 11-lapaz.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580919128E87005CD2F2 /* 11-lapaz.jpg */; }; 31 | 5DE3582519128E87005CD2F2 /* 12-villarrica.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580A19128E87005CD2F2 /* 12-villarrica.jpg */; }; 32 | 5DE3582619128E87005CD2F2 /* 13-lakevolcano.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580B19128E87005CD2F2 /* 13-lakevolcano.jpg */; }; 33 | 5DE3582719128E87005CD2F2 /* 14-denseforest.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580C19128E87005CD2F2 /* 14-denseforest.jpg */; }; 34 | 5DE3582819128E87005CD2F2 /* 15-glacier1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580D19128E87005CD2F2 /* 15-glacier1.jpg */; }; 35 | 5DE3582919128E87005CD2F2 /* 16-glacier2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580E19128E87005CD2F2 /* 16-glacier2.jpg */; }; 36 | 5DE3582A19128E87005CD2F2 /* 17-torresdelpaine1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3580F19128E87005CD2F2 /* 17-torresdelpaine1.jpg */; }; 37 | 5DE3582B19128E87005CD2F2 /* 18-torresdelpaine2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581019128E87005CD2F2 /* 18-torresdelpaine2.jpg */; }; 38 | 5DE3582C19128E87005CD2F2 /* 19-cat.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581119128E87005CD2F2 /* 19-cat.jpg */; }; 39 | 5DE3582D19128E87005CD2F2 /* 20-berlinskyline.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581219128E87005CD2F2 /* 20-berlinskyline.jpg */; }; 40 | 5DE3582E19128E87005CD2F2 /* 21-potsdamerplatz.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581319128E87005CD2F2 /* 21-potsdamerplatz.jpg */; }; 41 | 5DE3582F19128E87005CD2F2 /* 22-milchbar.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581419128E87005CD2F2 /* 22-milchbar.jpg */; }; 42 | 5DE3583019128E87005CD2F2 /* 23-berlinlights.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581519128E87005CD2F2 /* 23-berlinlights.jpg */; }; 43 | 5DE3583119128E87005CD2F2 /* 24-tvtower.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581619128E87005CD2F2 /* 24-tvtower.jpg */; }; 44 | 5DE3583219128E87005CD2F2 /* 25-winter.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581719128E87005CD2F2 /* 25-winter.jpg */; }; 45 | 5DE3583319128E87005CD2F2 /* 26-tree.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581819128E87005CD2F2 /* 26-tree.jpg */; }; 46 | 5DE3583419128E87005CD2F2 /* 27-beach.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3581919128E87005CD2F2 /* 27-beach.jpg */; }; 47 | 5DE358371912943E005CD2F2 /* ParallaxLayoutAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DE358361912943E005CD2F2 /* ParallaxLayoutAttributes.m */; }; 48 | 5DE3583919129913005CD2F2 /* Photos.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5DE3583819129913005CD2F2 /* Photos.plist */; }; 49 | /* End PBXBuildFile section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 5DE357C21912843E005CD2F2 /* ParallaxScrolling.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ParallaxScrolling.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 5DE357C51912843E005CD2F2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 54 | 5DE357C71912843E005CD2F2 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 55 | 5DE357C91912843E005CD2F2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 56 | 5DE357CD1912843E005CD2F2 /* ParallaxScrolling-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ParallaxScrolling-Info.plist"; sourceTree = ""; }; 57 | 5DE357CF1912843E005CD2F2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | 5DE357D11912843E005CD2F2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | 5DE357D31912843E005CD2F2 /* ParallaxScrolling-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ParallaxScrolling-Prefix.pch"; sourceTree = ""; }; 60 | 5DE357D41912843E005CD2F2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 61 | 5DE357D51912843E005CD2F2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 62 | 5DE357D71912843E005CD2F2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 63 | 5DE357DE1912843E005CD2F2 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 64 | 5DE357F4191284A3005CD2F2 /* PhotosCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotosCollectionViewController.h; sourceTree = ""; }; 65 | 5DE357F5191284A3005CD2F2 /* PhotosCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PhotosCollectionViewController.m; sourceTree = ""; }; 66 | 5DE357F7191284B2005CD2F2 /* ParallaxFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallaxFlowLayout.h; sourceTree = ""; }; 67 | 5DE357F8191284B2005CD2F2 /* ParallaxFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParallaxFlowLayout.m; sourceTree = ""; }; 68 | 5DE357FA191284CF005CD2F2 /* ParallaxPhotoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallaxPhotoCell.h; sourceTree = ""; }; 69 | 5DE357FB191284CF005CD2F2 /* ParallaxPhotoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParallaxPhotoCell.m; sourceTree = ""; }; 70 | 5DE357FF19128E87005CD2F2 /* 01-mallorca.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "01-mallorca.jpg"; sourceTree = ""; }; 71 | 5DE3580019128E87005CD2F2 /* 02-fishing.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "02-fishing.jpg"; sourceTree = ""; }; 72 | 5DE3580119128E87005CD2F2 /* 03-chili.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "03-chili.jpg"; sourceTree = ""; }; 73 | 5DE3580219128E87005CD2F2 /* 04-rice.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "04-rice.jpg"; sourceTree = ""; }; 74 | 5DE3580319128E87005CD2F2 /* 05-sweden.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "05-sweden.jpg"; sourceTree = ""; }; 75 | 5DE3580419128E87005CD2F2 /* 06-magicforest.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "06-magicforest.jpg"; sourceTree = ""; }; 76 | 5DE3580519128E87005CD2F2 /* 07-bird.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "07-bird.jpg"; sourceTree = ""; }; 77 | 5DE3580619128E87005CD2F2 /* 08-iguana.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "08-iguana.jpg"; sourceTree = ""; }; 78 | 5DE3580719128E87005CD2F2 /* 09-valley.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "09-valley.jpg"; sourceTree = ""; }; 79 | 5DE3580819128E87005CD2F2 /* 10-parrots.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "10-parrots.jpg"; sourceTree = ""; }; 80 | 5DE3580919128E87005CD2F2 /* 11-lapaz.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "11-lapaz.jpg"; sourceTree = ""; }; 81 | 5DE3580A19128E87005CD2F2 /* 12-villarrica.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "12-villarrica.jpg"; sourceTree = ""; }; 82 | 5DE3580B19128E87005CD2F2 /* 13-lakevolcano.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "13-lakevolcano.jpg"; sourceTree = ""; }; 83 | 5DE3580C19128E87005CD2F2 /* 14-denseforest.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "14-denseforest.jpg"; sourceTree = ""; }; 84 | 5DE3580D19128E87005CD2F2 /* 15-glacier1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "15-glacier1.jpg"; sourceTree = ""; }; 85 | 5DE3580E19128E87005CD2F2 /* 16-glacier2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "16-glacier2.jpg"; sourceTree = ""; }; 86 | 5DE3580F19128E87005CD2F2 /* 17-torresdelpaine1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "17-torresdelpaine1.jpg"; sourceTree = ""; }; 87 | 5DE3581019128E87005CD2F2 /* 18-torresdelpaine2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "18-torresdelpaine2.jpg"; sourceTree = ""; }; 88 | 5DE3581119128E87005CD2F2 /* 19-cat.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "19-cat.jpg"; sourceTree = ""; }; 89 | 5DE3581219128E87005CD2F2 /* 20-berlinskyline.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "20-berlinskyline.jpg"; sourceTree = ""; }; 90 | 5DE3581319128E87005CD2F2 /* 21-potsdamerplatz.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "21-potsdamerplatz.jpg"; sourceTree = ""; }; 91 | 5DE3581419128E87005CD2F2 /* 22-milchbar.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "22-milchbar.jpg"; sourceTree = ""; }; 92 | 5DE3581519128E87005CD2F2 /* 23-berlinlights.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "23-berlinlights.jpg"; sourceTree = ""; }; 93 | 5DE3581619128E87005CD2F2 /* 24-tvtower.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "24-tvtower.jpg"; sourceTree = ""; }; 94 | 5DE3581719128E87005CD2F2 /* 25-winter.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "25-winter.jpg"; sourceTree = ""; }; 95 | 5DE3581819128E87005CD2F2 /* 26-tree.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "26-tree.jpg"; sourceTree = ""; }; 96 | 5DE3581919128E87005CD2F2 /* 27-beach.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "27-beach.jpg"; sourceTree = ""; }; 97 | 5DE358351912943E005CD2F2 /* ParallaxLayoutAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallaxLayoutAttributes.h; sourceTree = ""; }; 98 | 5DE358361912943E005CD2F2 /* ParallaxLayoutAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParallaxLayoutAttributes.m; sourceTree = ""; }; 99 | 5DE3583819129913005CD2F2 /* Photos.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Photos.plist; path = ParallaxScrolling/Photos/Photos.plist; sourceTree = SOURCE_ROOT; }; 100 | /* End PBXFileReference section */ 101 | 102 | /* Begin PBXFrameworksBuildPhase section */ 103 | 5DE357BF1912843E005CD2F2 /* Frameworks */ = { 104 | isa = PBXFrameworksBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | 5DE357C81912843E005CD2F2 /* CoreGraphics.framework in Frameworks */, 108 | 5DE357CA1912843E005CD2F2 /* UIKit.framework in Frameworks */, 109 | 5DE357C61912843E005CD2F2 /* Foundation.framework in Frameworks */, 110 | ); 111 | runOnlyForDeploymentPostprocessing = 0; 112 | }; 113 | /* End PBXFrameworksBuildPhase section */ 114 | 115 | /* Begin PBXGroup section */ 116 | 5DE357B91912843E005CD2F2 = { 117 | isa = PBXGroup; 118 | children = ( 119 | 5DE357CB1912843E005CD2F2 /* ParallaxScrolling */, 120 | 5DE357C41912843E005CD2F2 /* Frameworks */, 121 | 5DE357C31912843E005CD2F2 /* Products */, 122 | ); 123 | sourceTree = ""; 124 | }; 125 | 5DE357C31912843E005CD2F2 /* Products */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 5DE357C21912843E005CD2F2 /* ParallaxScrolling.app */, 129 | ); 130 | name = Products; 131 | sourceTree = ""; 132 | }; 133 | 5DE357C41912843E005CD2F2 /* Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 5DE357C51912843E005CD2F2 /* Foundation.framework */, 137 | 5DE357C71912843E005CD2F2 /* CoreGraphics.framework */, 138 | 5DE357C91912843E005CD2F2 /* UIKit.framework */, 139 | 5DE357DE1912843E005CD2F2 /* XCTest.framework */, 140 | ); 141 | name = Frameworks; 142 | sourceTree = ""; 143 | }; 144 | 5DE357CB1912843E005CD2F2 /* ParallaxScrolling */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 5DE357D41912843E005CD2F2 /* AppDelegate.h */, 148 | 5DE357D51912843E005CD2F2 /* AppDelegate.m */, 149 | 5DE357F4191284A3005CD2F2 /* PhotosCollectionViewController.h */, 150 | 5DE357F5191284A3005CD2F2 /* PhotosCollectionViewController.m */, 151 | 5DE357F7191284B2005CD2F2 /* ParallaxFlowLayout.h */, 152 | 5DE357F8191284B2005CD2F2 /* ParallaxFlowLayout.m */, 153 | 5DE357FA191284CF005CD2F2 /* ParallaxPhotoCell.h */, 154 | 5DE357FB191284CF005CD2F2 /* ParallaxPhotoCell.m */, 155 | 5DE358351912943E005CD2F2 /* ParallaxLayoutAttributes.h */, 156 | 5DE358361912943E005CD2F2 /* ParallaxLayoutAttributes.m */, 157 | 5DE357D71912843E005CD2F2 /* Images.xcassets */, 158 | 5DE357CC1912843E005CD2F2 /* Supporting Files */, 159 | 5DE3583A19129944005CD2F2 /* Photos */, 160 | ); 161 | path = ParallaxScrolling; 162 | sourceTree = ""; 163 | }; 164 | 5DE357CC1912843E005CD2F2 /* Supporting Files */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 5DE357CD1912843E005CD2F2 /* ParallaxScrolling-Info.plist */, 168 | 5DE357CE1912843E005CD2F2 /* InfoPlist.strings */, 169 | 5DE357D11912843E005CD2F2 /* main.m */, 170 | 5DE357D31912843E005CD2F2 /* ParallaxScrolling-Prefix.pch */, 171 | ); 172 | name = "Supporting Files"; 173 | sourceTree = ""; 174 | }; 175 | 5DE3583A19129944005CD2F2 /* Photos */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 5DE3583819129913005CD2F2 /* Photos.plist */, 179 | 5DE357FF19128E87005CD2F2 /* 01-mallorca.jpg */, 180 | 5DE3580019128E87005CD2F2 /* 02-fishing.jpg */, 181 | 5DE3580119128E87005CD2F2 /* 03-chili.jpg */, 182 | 5DE3580219128E87005CD2F2 /* 04-rice.jpg */, 183 | 5DE3580319128E87005CD2F2 /* 05-sweden.jpg */, 184 | 5DE3580419128E87005CD2F2 /* 06-magicforest.jpg */, 185 | 5DE3580519128E87005CD2F2 /* 07-bird.jpg */, 186 | 5DE3580619128E87005CD2F2 /* 08-iguana.jpg */, 187 | 5DE3580719128E87005CD2F2 /* 09-valley.jpg */, 188 | 5DE3580819128E87005CD2F2 /* 10-parrots.jpg */, 189 | 5DE3580919128E87005CD2F2 /* 11-lapaz.jpg */, 190 | 5DE3580A19128E87005CD2F2 /* 12-villarrica.jpg */, 191 | 5DE3580B19128E87005CD2F2 /* 13-lakevolcano.jpg */, 192 | 5DE3580C19128E87005CD2F2 /* 14-denseforest.jpg */, 193 | 5DE3580D19128E87005CD2F2 /* 15-glacier1.jpg */, 194 | 5DE3580E19128E87005CD2F2 /* 16-glacier2.jpg */, 195 | 5DE3580F19128E87005CD2F2 /* 17-torresdelpaine1.jpg */, 196 | 5DE3581019128E87005CD2F2 /* 18-torresdelpaine2.jpg */, 197 | 5DE3581119128E87005CD2F2 /* 19-cat.jpg */, 198 | 5DE3581219128E87005CD2F2 /* 20-berlinskyline.jpg */, 199 | 5DE3581319128E87005CD2F2 /* 21-potsdamerplatz.jpg */, 200 | 5DE3581419128E87005CD2F2 /* 22-milchbar.jpg */, 201 | 5DE3581519128E87005CD2F2 /* 23-berlinlights.jpg */, 202 | 5DE3581619128E87005CD2F2 /* 24-tvtower.jpg */, 203 | 5DE3581719128E87005CD2F2 /* 25-winter.jpg */, 204 | 5DE3581819128E87005CD2F2 /* 26-tree.jpg */, 205 | 5DE3581919128E87005CD2F2 /* 27-beach.jpg */, 206 | ); 207 | path = Photos; 208 | sourceTree = ""; 209 | }; 210 | /* End PBXGroup section */ 211 | 212 | /* Begin PBXNativeTarget section */ 213 | 5DE357C11912843E005CD2F2 /* ParallaxScrolling */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = 5DE357EE1912843E005CD2F2 /* Build configuration list for PBXNativeTarget "ParallaxScrolling" */; 216 | buildPhases = ( 217 | 5DE357BE1912843E005CD2F2 /* Sources */, 218 | 5DE357BF1912843E005CD2F2 /* Frameworks */, 219 | 5DE357C01912843E005CD2F2 /* Resources */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | ); 225 | name = ParallaxScrolling; 226 | productName = ParallaxScrolling; 227 | productReference = 5DE357C21912843E005CD2F2 /* ParallaxScrolling.app */; 228 | productType = "com.apple.product-type.application"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | 5DE357BA1912843E005CD2F2 /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | LastUpgradeCheck = 0510; 237 | ORGANIZATIONNAME = "Ole Begemann"; 238 | }; 239 | buildConfigurationList = 5DE357BD1912843E005CD2F2 /* Build configuration list for PBXProject "ParallaxScrolling" */; 240 | compatibilityVersion = "Xcode 3.2"; 241 | developmentRegion = English; 242 | hasScannedForEncodings = 0; 243 | knownRegions = ( 244 | en, 245 | ); 246 | mainGroup = 5DE357B91912843E005CD2F2; 247 | productRefGroup = 5DE357C31912843E005CD2F2 /* Products */; 248 | projectDirPath = ""; 249 | projectRoot = ""; 250 | targets = ( 251 | 5DE357C11912843E005CD2F2 /* ParallaxScrolling */, 252 | ); 253 | }; 254 | /* End PBXProject section */ 255 | 256 | /* Begin PBXResourcesBuildPhase section */ 257 | 5DE357C01912843E005CD2F2 /* Resources */ = { 258 | isa = PBXResourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 5DE3582A19128E87005CD2F2 /* 17-torresdelpaine1.jpg in Resources */, 262 | 5DE357D01912843E005CD2F2 /* InfoPlist.strings in Resources */, 263 | 5DE3582819128E87005CD2F2 /* 15-glacier1.jpg in Resources */, 264 | 5DE3582619128E87005CD2F2 /* 13-lakevolcano.jpg in Resources */, 265 | 5DE3581F19128E87005CD2F2 /* 06-magicforest.jpg in Resources */, 266 | 5DE3583219128E87005CD2F2 /* 25-winter.jpg in Resources */, 267 | 5DE3583019128E87005CD2F2 /* 23-berlinlights.jpg in Resources */, 268 | 5DE3581D19128E87005CD2F2 /* 04-rice.jpg in Resources */, 269 | 5DE357D81912843E005CD2F2 /* Images.xcassets in Resources */, 270 | 5DE3583119128E87005CD2F2 /* 24-tvtower.jpg in Resources */, 271 | 5DE3582419128E87005CD2F2 /* 11-lapaz.jpg in Resources */, 272 | 5DE3582B19128E87005CD2F2 /* 18-torresdelpaine2.jpg in Resources */, 273 | 5DE3582F19128E87005CD2F2 /* 22-milchbar.jpg in Resources */, 274 | 5DE3582C19128E87005CD2F2 /* 19-cat.jpg in Resources */, 275 | 5DE3581E19128E87005CD2F2 /* 05-sweden.jpg in Resources */, 276 | 5DE3582D19128E87005CD2F2 /* 20-berlinskyline.jpg in Resources */, 277 | 5DE3582719128E87005CD2F2 /* 14-denseforest.jpg in Resources */, 278 | 5DE3583419128E87005CD2F2 /* 27-beach.jpg in Resources */, 279 | 5DE3581A19128E87005CD2F2 /* 01-mallorca.jpg in Resources */, 280 | 5DE3582219128E87005CD2F2 /* 09-valley.jpg in Resources */, 281 | 5DE3582019128E87005CD2F2 /* 07-bird.jpg in Resources */, 282 | 5DE3583319128E87005CD2F2 /* 26-tree.jpg in Resources */, 283 | 5DE3582319128E87005CD2F2 /* 10-parrots.jpg in Resources */, 284 | 5DE3582119128E87005CD2F2 /* 08-iguana.jpg in Resources */, 285 | 5DE3581C19128E87005CD2F2 /* 03-chili.jpg in Resources */, 286 | 5DE3582919128E87005CD2F2 /* 16-glacier2.jpg in Resources */, 287 | 5DE3581B19128E87005CD2F2 /* 02-fishing.jpg in Resources */, 288 | 5DE3582E19128E87005CD2F2 /* 21-potsdamerplatz.jpg in Resources */, 289 | 5DE3582519128E87005CD2F2 /* 12-villarrica.jpg in Resources */, 290 | 5DE3583919129913005CD2F2 /* Photos.plist in Resources */, 291 | ); 292 | runOnlyForDeploymentPostprocessing = 0; 293 | }; 294 | /* End PBXResourcesBuildPhase section */ 295 | 296 | /* Begin PBXSourcesBuildPhase section */ 297 | 5DE357BE1912843E005CD2F2 /* Sources */ = { 298 | isa = PBXSourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | 5DE358371912943E005CD2F2 /* ParallaxLayoutAttributes.m in Sources */, 302 | 5DE357D61912843E005CD2F2 /* AppDelegate.m in Sources */, 303 | 5DE357F6191284A3005CD2F2 /* PhotosCollectionViewController.m in Sources */, 304 | 5DE357F9191284B2005CD2F2 /* ParallaxFlowLayout.m in Sources */, 305 | 5DE357FC191284D0005CD2F2 /* ParallaxPhotoCell.m in Sources */, 306 | 5DE357D21912843E005CD2F2 /* main.m in Sources */, 307 | ); 308 | runOnlyForDeploymentPostprocessing = 0; 309 | }; 310 | /* End PBXSourcesBuildPhase section */ 311 | 312 | /* Begin PBXVariantGroup section */ 313 | 5DE357CE1912843E005CD2F2 /* InfoPlist.strings */ = { 314 | isa = PBXVariantGroup; 315 | children = ( 316 | 5DE357CF1912843E005CD2F2 /* en */, 317 | ); 318 | name = InfoPlist.strings; 319 | sourceTree = ""; 320 | }; 321 | /* End PBXVariantGroup section */ 322 | 323 | /* Begin XCBuildConfiguration section */ 324 | 5DE357EC1912843E005CD2F2 /* Debug */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ALWAYS_SEARCH_USER_PATHS = NO; 328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 329 | CLANG_CXX_LIBRARY = "libc++"; 330 | CLANG_ENABLE_MODULES = YES; 331 | CLANG_ENABLE_OBJC_ARC = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 335 | CLANG_WARN_EMPTY_BODY = YES; 336 | CLANG_WARN_ENUM_CONVERSION = YES; 337 | CLANG_WARN_INT_CONVERSION = YES; 338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 341 | COPY_PHASE_STRIP = NO; 342 | GCC_C_LANGUAGE_STANDARD = gnu99; 343 | GCC_DYNAMIC_NO_PIC = NO; 344 | GCC_OPTIMIZATION_LEVEL = 0; 345 | GCC_PREPROCESSOR_DEFINITIONS = ( 346 | "DEBUG=1", 347 | "$(inherited)", 348 | ); 349 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 352 | GCC_WARN_UNDECLARED_SELECTOR = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | GCC_WARN_UNUSED_FUNCTION = YES; 355 | GCC_WARN_UNUSED_VARIABLE = YES; 356 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 357 | ONLY_ACTIVE_ARCH = YES; 358 | SDKROOT = iphoneos; 359 | }; 360 | name = Debug; 361 | }; 362 | 5DE357ED1912843E005CD2F2 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ALWAYS_SEARCH_USER_PATHS = NO; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_CONSTANT_CONVERSION = YES; 372 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 373 | CLANG_WARN_EMPTY_BODY = YES; 374 | CLANG_WARN_ENUM_CONVERSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 377 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 378 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 379 | COPY_PHASE_STRIP = YES; 380 | ENABLE_NS_ASSERTIONS = NO; 381 | GCC_C_LANGUAGE_STANDARD = gnu99; 382 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 383 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 384 | GCC_WARN_UNDECLARED_SELECTOR = YES; 385 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 386 | GCC_WARN_UNUSED_FUNCTION = YES; 387 | GCC_WARN_UNUSED_VARIABLE = YES; 388 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 389 | SDKROOT = iphoneos; 390 | VALIDATE_PRODUCT = YES; 391 | }; 392 | name = Release; 393 | }; 394 | 5DE357EF1912843E005CD2F2 /* Debug */ = { 395 | isa = XCBuildConfiguration; 396 | buildSettings = { 397 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 398 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 399 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 400 | GCC_PREFIX_HEADER = "ParallaxScrolling/ParallaxScrolling-Prefix.pch"; 401 | INFOPLIST_FILE = "ParallaxScrolling/ParallaxScrolling-Info.plist"; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | WRAPPER_EXTENSION = app; 404 | }; 405 | name = Debug; 406 | }; 407 | 5DE357F01912843E005CD2F2 /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 411 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 412 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 413 | GCC_PREFIX_HEADER = "ParallaxScrolling/ParallaxScrolling-Prefix.pch"; 414 | INFOPLIST_FILE = "ParallaxScrolling/ParallaxScrolling-Info.plist"; 415 | PRODUCT_NAME = "$(TARGET_NAME)"; 416 | WRAPPER_EXTENSION = app; 417 | }; 418 | name = Release; 419 | }; 420 | /* End XCBuildConfiguration section */ 421 | 422 | /* Begin XCConfigurationList section */ 423 | 5DE357BD1912843E005CD2F2 /* Build configuration list for PBXProject "ParallaxScrolling" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 5DE357EC1912843E005CD2F2 /* Debug */, 427 | 5DE357ED1912843E005CD2F2 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | 5DE357EE1912843E005CD2F2 /* Build configuration list for PBXNativeTarget "ParallaxScrolling" */ = { 433 | isa = XCConfigurationList; 434 | buildConfigurations = ( 435 | 5DE357EF1912843E005CD2F2 /* Debug */, 436 | 5DE357F01912843E005CD2F2 /* Release */, 437 | ); 438 | defaultConfigurationIsVisible = 0; 439 | defaultConfigurationName = Release; 440 | }; 441 | /* End XCConfigurationList section */ 442 | }; 443 | rootObject = 5DE357BA1912843E005CD2F2 /* Project object */; 444 | } 445 | -------------------------------------------------------------------------------- /ParallaxScrolling/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ParallaxScrolling/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "PhotosCollectionViewController.h" 11 | 12 | @implementation AppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 15 | { 16 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 17 | self.window.backgroundColor = [UIColor whiteColor]; 18 | 19 | PhotosCollectionViewController *viewController = [[PhotosCollectionViewController alloc] init]; 20 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; 21 | self.window.rootViewController = navigationController; 22 | 23 | [self.window makeKeyAndVisible]; 24 | return YES; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ParallaxScrolling/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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /ParallaxScrolling/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxFlowLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxFlowLayout.h 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ParallaxFlowLayout : UICollectionViewFlowLayout 12 | 13 | @property (nonatomic, readonly) CGFloat maxParallaxOffset; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxFlowLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxFlowLayout.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | #import "ParallaxFlowLayout.h" 10 | #import "ParallaxLayoutAttributes.h" 11 | 12 | static const CGFloat MaxParallaxOffset = 30.0; 13 | 14 | @implementation ParallaxFlowLayout 15 | 16 | + (Class)layoutAttributesClass 17 | { 18 | return [ParallaxLayoutAttributes class]; 19 | } 20 | 21 | - (CGFloat)maxParallaxOffset 22 | { 23 | return MaxParallaxOffset; 24 | } 25 | 26 | - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 27 | { 28 | return YES; 29 | } 30 | 31 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 32 | { 33 | NSArray *layoutAttributesArray = [super layoutAttributesForElementsInRect:rect]; 34 | for (ParallaxLayoutAttributes *layoutAttributes in layoutAttributesArray) { 35 | if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { 36 | layoutAttributes.parallaxOffset = [self parallaxOffsetForLayoutAttributes:layoutAttributes]; 37 | } 38 | } 39 | return layoutAttributesArray; 40 | } 41 | 42 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 43 | { 44 | ParallaxLayoutAttributes *layoutAttributes = (ParallaxLayoutAttributes *)[super layoutAttributesForItemAtIndexPath:indexPath]; 45 | layoutAttributes.parallaxOffset = [self parallaxOffsetForLayoutAttributes:layoutAttributes]; 46 | return layoutAttributes; 47 | } 48 | 49 | - (CGPoint)parallaxOffsetForLayoutAttributes:(ParallaxLayoutAttributes *)layoutAttributes 50 | { 51 | NSParameterAssert(layoutAttributes != nil); 52 | NSParameterAssert([layoutAttributes isKindOfClass:[ParallaxLayoutAttributes class]]); 53 | 54 | CGRect bounds = self.collectionView.bounds; 55 | CGPoint boundsCenter = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); 56 | CGPoint cellCenter = layoutAttributes.center; 57 | CGPoint offsetFromCenter = CGPointMake(boundsCenter.x - cellCenter.x, boundsCenter.y - cellCenter.y); 58 | 59 | CGSize cellSize = layoutAttributes.size; 60 | CGFloat maxVerticalOffsetWhereCellIsStillVisible = (bounds.size.height / 2) + (cellSize.height / 2); 61 | CGFloat scaleFactor = self.maxParallaxOffset / maxVerticalOffsetWhereCellIsStillVisible; 62 | 63 | CGPoint parallaxOffset = CGPointMake(0.0, offsetFromCenter.y * scaleFactor); 64 | 65 | return parallaxOffset; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxLayoutAttributes.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxLayoutAttributes.h 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ParallaxLayoutAttributes : UICollectionViewLayoutAttributes 12 | 13 | @property (nonatomic) CGPoint parallaxOffset; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxLayoutAttributes.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxLayoutAttributes.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | #import "ParallaxLayoutAttributes.h" 10 | 11 | @implementation ParallaxLayoutAttributes 12 | 13 | - (id)copyWithZone:(NSZone *)zone 14 | { 15 | ParallaxLayoutAttributes *copy = [super copyWithZone:zone]; 16 | NSAssert([copy isKindOfClass:[self class]], @"copy must have the same class"); 17 | copy.parallaxOffset = self.parallaxOffset; 18 | return copy; 19 | } 20 | 21 | - (BOOL)isEqual:(id)object 22 | { 23 | if (![object isKindOfClass:[ParallaxLayoutAttributes class]]) { 24 | return NO; 25 | } 26 | 27 | ParallaxLayoutAttributes *otherObject = object; 28 | if (!CGPointEqualToPoint(self.parallaxOffset, otherObject.parallaxOffset)) { 29 | return NO; 30 | } 31 | return [super isEqual:otherObject]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxPhotoCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxPhotoCell.h 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ParallaxPhotoCell : UICollectionViewCell 12 | 13 | @property (nonatomic, strong, readonly) UIImageView *imageView; 14 | @property (nonatomic) CGFloat maxParallaxOffset; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxPhotoCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParallaxPhotoCell.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | #import "ParallaxPhotoCell.h" 10 | #import "ParallaxLayoutAttributes.h" 11 | 12 | @interface ParallaxPhotoCell () 13 | 14 | @property (nonatomic, strong) NSLayoutConstraint *imageViewHeightConstraint; 15 | @property (nonatomic, strong) NSLayoutConstraint *imageViewCenterYConstraint; 16 | 17 | @end 18 | 19 | 20 | @implementation ParallaxPhotoCell 21 | 22 | - (id)initWithFrame:(CGRect)frame 23 | { 24 | self = [super initWithFrame:frame]; 25 | if (self == nil) { 26 | return nil; 27 | } 28 | 29 | self.clipsToBounds = YES; 30 | 31 | [self setupImageView]; 32 | [self setupConstraints]; 33 | [self setNeedsUpdateConstraints]; 34 | 35 | return self; 36 | } 37 | 38 | - (void)setupImageView 39 | { 40 | _imageView = [[UIImageView alloc] initWithImage:nil]; 41 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 42 | [self.contentView addSubview:_imageView]; 43 | } 44 | 45 | - (void)setupConstraints 46 | { 47 | self.imageView.translatesAutoresizingMaskIntoConstraints = NO; 48 | 49 | // Horizontal constraints for image view 50 | [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1 constant:0]]; 51 | [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1 constant:0]]; 52 | 53 | // Vertical constraints for image view 54 | self.imageViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]; 55 | self.imageViewCenterYConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; 56 | [self.contentView addConstraint:self.imageViewHeightConstraint]; 57 | [self.contentView addConstraint:self.imageViewCenterYConstraint]; 58 | } 59 | 60 | - (void)updateConstraints 61 | { 62 | [super updateConstraints]; 63 | 64 | // Make sure image view is tall enough to cover maxParallaxOffset in both directions 65 | self.imageViewHeightConstraint.constant = 2 * self.maxParallaxOffset; 66 | } 67 | 68 | - (void)setMaxParallaxOffset:(CGFloat)maxParallaxOffset 69 | { 70 | _maxParallaxOffset = maxParallaxOffset; 71 | [self setNeedsUpdateConstraints]; 72 | } 73 | 74 | - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes 75 | { 76 | [super applyLayoutAttributes:layoutAttributes]; 77 | 78 | NSParameterAssert(layoutAttributes != nil); 79 | NSParameterAssert([layoutAttributes isKindOfClass:[ParallaxLayoutAttributes class]]); 80 | 81 | ParallaxLayoutAttributes *parallaxLayoutAttributes = (ParallaxLayoutAttributes *)layoutAttributes; 82 | self.imageViewCenterYConstraint.constant = parallaxLayoutAttributes.parallaxOffset.y; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxScrolling-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.olebegemann.${PRODUCT_NAME:rfc1034identifier} 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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ParallaxScrolling/ParallaxScrolling-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/01-mallorca.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/01-mallorca.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/02-fishing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/02-fishing.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/03-chili.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/03-chili.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/04-rice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/04-rice.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/05-sweden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/05-sweden.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/06-magicforest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/06-magicforest.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/07-bird.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/07-bird.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/08-iguana.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/08-iguana.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/09-valley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/09-valley.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/10-parrots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/10-parrots.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/11-lapaz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/11-lapaz.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/12-villarrica.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/12-villarrica.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/13-lakevolcano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/13-lakevolcano.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/14-denseforest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/14-denseforest.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/15-glacier1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/15-glacier1.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/16-glacier2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/16-glacier2.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/17-torresdelpaine1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/17-torresdelpaine1.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/18-torresdelpaine2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/18-torresdelpaine2.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/19-cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/19-cat.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/20-berlinskyline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/20-berlinskyline.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/21-potsdamerplatz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/21-potsdamerplatz.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/22-milchbar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/22-milchbar.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/23-berlinlights.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/23-berlinlights.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/24-tvtower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/24-tvtower.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/25-winter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/25-winter.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/26-tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/26-tree.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/27-beach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ole/CollectionViewParallaxScrolling/574f7f4154990cc145c961cda8edb01c59bba01f/ParallaxScrolling/Photos/27-beach.jpg -------------------------------------------------------------------------------- /ParallaxScrolling/Photos/Photos.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | photos 6 | 7 | 8 | filename 9 | 01-mallorca.jpg 10 | height 11 | 480 12 | width 13 | 640 14 | 15 | 16 | filename 17 | 02-fishing.jpg 18 | height 19 | 480 20 | width 21 | 640 22 | 23 | 24 | filename 25 | 03-chili.jpg 26 | height 27 | 480 28 | width 29 | 640 30 | 31 | 32 | filename 33 | 04-rice.jpg 34 | height 35 | 480 36 | width 37 | 640 38 | 39 | 40 | filename 41 | 05-sweden.jpg 42 | height 43 | 308 44 | width 45 | 640 46 | 47 | 48 | filename 49 | 06-magicforest.jpg 50 | height 51 | 426 52 | width 53 | 640 54 | 55 | 56 | filename 57 | 07-bird.jpg 58 | height 59 | 426 60 | width 61 | 640 62 | 63 | 64 | filename 65 | 08-iguana.jpg 66 | height 67 | 426 68 | width 69 | 640 70 | 71 | 72 | filename 73 | 09-valley.jpg 74 | height 75 | 426 76 | width 77 | 640 78 | 79 | 80 | filename 81 | 10-parrots.jpg 82 | height 83 | 360 84 | width 85 | 640 86 | 87 | 88 | filename 89 | 11-lapaz.jpg 90 | height 91 | 426 92 | width 93 | 640 94 | 95 | 96 | filename 97 | 12-villarrica.jpg 98 | height 99 | 426 100 | width 101 | 640 102 | 103 | 104 | filename 105 | 13-lakevolcano.jpg 106 | height 107 | 411 108 | width 109 | 640 110 | 111 | 112 | filename 113 | 14-denseforest.jpg 114 | height 115 | 426 116 | width 117 | 640 118 | 119 | 120 | filename 121 | 15-glacier1.jpg 122 | height 123 | 426 124 | width 125 | 640 126 | 127 | 128 | filename 129 | 16-glacier2.jpg 130 | height 131 | 360 132 | width 133 | 640 134 | 135 | 136 | filename 137 | 17-torresdelpaine1.jpg 138 | height 139 | 360 140 | width 141 | 640 142 | 143 | 144 | filename 145 | 18-torresdelpaine2.jpg 146 | height 147 | 426 148 | width 149 | 640 150 | 151 | 152 | filename 153 | 19-cat.jpg 154 | height 155 | 426 156 | width 157 | 640 158 | 159 | 160 | filename 161 | 20-berlinskyline.jpg 162 | height 163 | 426 164 | width 165 | 640 166 | 167 | 168 | filename 169 | 21-potsdamerplatz.jpg 170 | height 171 | 400 172 | width 173 | 640 174 | 175 | 176 | filename 177 | 22-milchbar.jpg 178 | height 179 | 436 180 | width 181 | 640 182 | 183 | 184 | filename 185 | 23-berlinlights.jpg 186 | height 187 | 512 188 | width 189 | 640 190 | 191 | 192 | filename 193 | 24-tvtower.jpg 194 | height 195 | 320 196 | width 197 | 640 198 | 199 | 200 | filename 201 | 25-winter.jpg 202 | height 203 | 360 204 | width 205 | 640 206 | 207 | 208 | filename 209 | 26-tree.jpg 210 | height 211 | 478 212 | width 213 | 640 214 | 215 | 216 | filename 217 | 27-beach.jpg 218 | height 219 | 426 220 | width 221 | 640 222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /ParallaxScrolling/PhotosCollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhotosCollectionViewController.h 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface PhotosCollectionViewController : UICollectionViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ParallaxScrolling/PhotosCollectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PhotosCollectionViewController.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | #import "PhotosCollectionViewController.h" 10 | #import "ParallaxFlowLayout.h" 11 | #import "ParallaxPhotoCell.h" 12 | 13 | @interface PhotosCollectionViewController () 14 | 15 | @property (nonatomic, copy) NSArray *photos; 16 | 17 | @end 18 | 19 | 20 | @implementation PhotosCollectionViewController 21 | 22 | - (id)init 23 | { 24 | ParallaxFlowLayout *layout = [[ParallaxFlowLayout alloc] init]; 25 | layout.minimumLineSpacing = 16; 26 | layout.sectionInset = UIEdgeInsetsMake(16, 16, 16, 16); 27 | 28 | self = [super initWithCollectionViewLayout:layout]; 29 | 30 | if (self == nil) { 31 | return nil; 32 | } 33 | 34 | self.title = @"Photos"; 35 | 36 | NSDictionary *photosDict = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"Photos" withExtension:@"plist"]]; 37 | self.photos = photosDict[@"photos"]; 38 | 39 | return self; 40 | } 41 | 42 | - (id)initWithCollectionViewLayout:(UICollectionViewLayout *)layout 43 | { 44 | return [self init]; 45 | } 46 | 47 | - (void)viewDidLoad 48 | { 49 | [super viewDidLoad]; 50 | self.collectionView.backgroundColor = [UIColor whiteColor]; 51 | [self.collectionView registerClass:[ParallaxPhotoCell class] forCellWithReuseIdentifier:@"PhotoCell"]; 52 | } 53 | 54 | #pragma mark - UICollectionViewDataSource 55 | 56 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView 57 | { 58 | return 1; 59 | } 60 | 61 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 62 | { 63 | return [self.photos count]; 64 | } 65 | 66 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 67 | { 68 | ParallaxPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PhotoCell" forIndexPath:indexPath]; 69 | 70 | NSDictionary *photo = self.photos[indexPath.item]; 71 | NSString *photoFilename = photo[@"filename"]; 72 | UIImage *image = [UIImage imageNamed:photoFilename]; 73 | cell.imageView.image = image; 74 | 75 | // Pass the maximum parallax offset to the cell. 76 | // The cell needs this information to configure the constraints for its image view. 77 | ParallaxFlowLayout *layout = (ParallaxFlowLayout *)self.collectionViewLayout; 78 | cell.maxParallaxOffset = layout.maxParallaxOffset; 79 | 80 | return cell; 81 | } 82 | 83 | #pragma mark - UICollectionViewDelegateFlowLayout 84 | 85 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 86 | { 87 | NSDictionary *photo = self.photos[indexPath.item]; 88 | CGFloat imageWidth = [photo[@"width"] floatValue]; 89 | CGFloat imageHeight = [photo[@"height"] floatValue]; 90 | 91 | // Compute cell size according to image aspect ratio. 92 | // Cell height must take maximum possible parallax offset into account. 93 | ParallaxFlowLayout *layout = (ParallaxFlowLayout *)self.collectionViewLayout; 94 | CGFloat cellWidth = CGRectGetWidth(self.collectionView.bounds) - layout.sectionInset.left - layout.sectionInset.right; 95 | CGFloat cellHeight = floor(cellWidth / imageWidth * imageHeight) - (2 * layout.maxParallaxOffset); 96 | return CGSizeMake(cellWidth, cellHeight); 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /ParallaxScrolling/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ParallaxScrolling/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ParallaxScrolling 4 | // 5 | // Created by Ole Begemann on 01.05.14. 6 | // Copyright (c) 2014 Ole Begemann. All rights reserved. 7 | // 8 | 9 | @import UIKit; 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 | # CollectionViewParallaxScrolling 2 | 3 | An implementation of a custom `UICollectionViewLayout` that demonstrates WhatsApp-style parallax scrolling in a collection view. 4 | 5 | Written by [Ole Begemann](http://oleb.net), May 2014. 6 | 7 | Please read [the accompanying blog post](http://oleb.net/blog/2014/04/parallax-scrolling-collectionview/) for more information. 8 | 9 | ## Demo Video 10 | 11 | 14 | 15 | [Download the demo video (H.264)](http://oleb.net/media/parallax-scrolling-640x1136.m4v) 16 | 17 | ## Photos 18 | 19 | All photos used in the demo app by Ole Begemann. Check out my [Flickr account](https://www.flickr.com/photos/ole/) for more. 20 | --------------------------------------------------------------------------------