├── .gitignore ├── BFPaperCollectionViewCell.podspec ├── BFPaperCollectionViewCell.xcodeproj └── project.pbxproj ├── BFPaperCollectionViewCell.xcworkspace └── contents.xcworkspacedata ├── BFPaperCollectionViewCell ├── BFPaperAppDelegate.h ├── BFPaperAppDelegate.m ├── BFPaperCollectionViewCell-Info.plist ├── BFPaperCollectionViewCell-Prefix.pch ├── BFPaperViewController.h ├── BFPaperViewController.m ├── Base.lproj │ └── Main.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ └── bg-blue-white-arrow.imageset │ │ ├── Contents.json │ │ └── bg-blue-white-arrow.png ├── Launch Screen.storyboard ├── SubclassOfPaperCollectionViewCell.h ├── SubclassOfPaperCollectionViewCell.m ├── en.lproj │ └── InfoPlist.strings └── main.m ├── BFPaperCollectionViewCellTests ├── BFPaperCollectionViewCellTests-Info.plist ├── BFPaperTableViewCellTests.m └── en.lproj │ └── InfoPlist.strings ├── CHANGELOG.md ├── Classes ├── BFPaperCollectionViewCell.h └── BFPaperCollectionViewCell.m ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate -------------------------------------------------------------------------------- /BFPaperCollectionViewCell.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "BFPaperCollectionViewCell" 4 | s.version = "2.3.7" 5 | s.summary = "A flat button for use in a collection view cell inspired by Google Material Design's Paper theme." 6 | s.homepage = "https://github.com/bfeher/BFPaperCollectionViewCell" 7 | s.license = { :type => 'MIT', :file => 'LICENSE.md' } 8 | s.author = { "Bence Feher" => "ben.feher@gmail.com" } 9 | s.source = { :git => "https://github.com/bfeher/BFPaperCollectionViewCell.git", :tag => "2.3.7" } 10 | s.platform = :ios, '7.0' 11 | 12 | 13 | s.source_files = 'Classes/*.{h,m}' 14 | s.requires_arc = true 15 | 16 | end 17 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 505849251D5323A100FEE8FE /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 505849241D5323A100FEE8FE /* Launch Screen.storyboard */; }; 11 | F42B5BA91978DD0000D6F4B5 /* BFPaperCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F42B5BA81978DD0000D6F4B5 /* BFPaperCollectionViewCell.m */; }; 12 | F4533CD81A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F4533CD71A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.m */; }; 13 | F48E73AE1977B45700982A46 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73AD1977B45700982A46 /* Foundation.framework */; }; 14 | F48E73B01977B45700982A46 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73AF1977B45700982A46 /* CoreGraphics.framework */; }; 15 | F48E73B21977B45700982A46 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73B11977B45700982A46 /* UIKit.framework */; }; 16 | F48E73B81977B45700982A46 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F48E73B61977B45700982A46 /* InfoPlist.strings */; }; 17 | F48E73BA1977B45700982A46 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F48E73B91977B45700982A46 /* main.m */; }; 18 | F48E73BE1977B45700982A46 /* BFPaperAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F48E73BD1977B45700982A46 /* BFPaperAppDelegate.m */; }; 19 | F48E73C11977B45700982A46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F48E73BF1977B45700982A46 /* Main.storyboard */; }; 20 | F48E73C41977B45700982A46 /* BFPaperViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F48E73C31977B45700982A46 /* BFPaperViewController.m */; }; 21 | F48E73C61977B45700982A46 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F48E73C51977B45700982A46 /* Images.xcassets */; }; 22 | F48E73CD1977B45700982A46 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73CC1977B45700982A46 /* XCTest.framework */; }; 23 | F48E73CE1977B45700982A46 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73AD1977B45700982A46 /* Foundation.framework */; }; 24 | F48E73CF1977B45700982A46 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F48E73B11977B45700982A46 /* UIKit.framework */; }; 25 | F48E73D71977B45700982A46 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F48E73D51977B45700982A46 /* InfoPlist.strings */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | F48E73D01977B45700982A46 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = F48E73A21977B45700982A46 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = F48E73A91977B45700982A46; 34 | remoteInfo = BFPaperCollectionViewCell; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 505849241D5323A100FEE8FE /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 40 | F42B5BA71978DD0000D6F4B5 /* BFPaperCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BFPaperCollectionViewCell.h; path = ../Classes/BFPaperCollectionViewCell.h; sourceTree = ""; }; 41 | F42B5BA81978DD0000D6F4B5 /* BFPaperCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BFPaperCollectionViewCell.m; path = ../Classes/BFPaperCollectionViewCell.m; sourceTree = ""; }; 42 | F4533CD61A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubclassOfPaperCollectionViewCell.h; sourceTree = ""; }; 43 | F4533CD71A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SubclassOfPaperCollectionViewCell.m; sourceTree = ""; }; 44 | F48E73AA1977B45700982A46 /* BFPaperCollectionViewCell.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BFPaperCollectionViewCell.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | F48E73AD1977B45700982A46 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | F48E73AF1977B45700982A46 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | F48E73B11977B45700982A46 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | F48E73B51977B45700982A46 /* BFPaperCollectionViewCell-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BFPaperCollectionViewCell-Info.plist"; sourceTree = ""; }; 49 | F48E73B71977B45700982A46 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | F48E73B91977B45700982A46 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | F48E73BB1977B45700982A46 /* BFPaperCollectionViewCell-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BFPaperCollectionViewCell-Prefix.pch"; sourceTree = ""; }; 52 | F48E73BC1977B45700982A46 /* BFPaperAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BFPaperAppDelegate.h; sourceTree = ""; }; 53 | F48E73BD1977B45700982A46 /* BFPaperAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BFPaperAppDelegate.m; sourceTree = ""; }; 54 | F48E73C01977B45700982A46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | F48E73C21977B45700982A46 /* BFPaperViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BFPaperViewController.h; sourceTree = ""; }; 56 | F48E73C31977B45700982A46 /* BFPaperViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BFPaperViewController.m; sourceTree = ""; }; 57 | F48E73C51977B45700982A46 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 58 | F48E73CB1977B45700982A46 /* BFPaperCollectionViewCellTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BFPaperCollectionViewCellTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | F48E73CC1977B45700982A46 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 60 | F48E73D41977B45700982A46 /* BFPaperCollectionViewCellTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "BFPaperCollectionViewCellTests-Info.plist"; sourceTree = ""; }; 61 | F48E73D61977B45700982A46 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | F48E73A71977B45700982A46 /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | F48E73B01977B45700982A46 /* CoreGraphics.framework in Frameworks */, 70 | F48E73B21977B45700982A46 /* UIKit.framework in Frameworks */, 71 | F48E73AE1977B45700982A46 /* Foundation.framework in Frameworks */, 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | F48E73C81977B45700982A46 /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | F48E73CD1977B45700982A46 /* XCTest.framework in Frameworks */, 80 | F48E73CF1977B45700982A46 /* UIKit.framework in Frameworks */, 81 | F48E73CE1977B45700982A46 /* Foundation.framework in Frameworks */, 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | F48E73A11977B45700982A46 = { 89 | isa = PBXGroup; 90 | children = ( 91 | F48E73E21977BAF000982A46 /* Classes */, 92 | F48E73B31977B45700982A46 /* BFPaperCollectionViewCell */, 93 | F48E73D21977B45700982A46 /* BFPaperCollectionViewCellTests */, 94 | F48E73AC1977B45700982A46 /* Frameworks */, 95 | F48E73AB1977B45700982A46 /* Products */, 96 | ); 97 | sourceTree = ""; 98 | }; 99 | F48E73AB1977B45700982A46 /* Products */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | F48E73AA1977B45700982A46 /* BFPaperCollectionViewCell.app */, 103 | F48E73CB1977B45700982A46 /* BFPaperCollectionViewCellTests.xctest */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | F48E73AC1977B45700982A46 /* Frameworks */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | F48E73AD1977B45700982A46 /* Foundation.framework */, 112 | F48E73AF1977B45700982A46 /* CoreGraphics.framework */, 113 | F48E73B11977B45700982A46 /* UIKit.framework */, 114 | F48E73CC1977B45700982A46 /* XCTest.framework */, 115 | ); 116 | name = Frameworks; 117 | sourceTree = ""; 118 | }; 119 | F48E73B31977B45700982A46 /* BFPaperCollectionViewCell */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | F4533CD61A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.h */, 123 | F4533CD71A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.m */, 124 | F48E73BC1977B45700982A46 /* BFPaperAppDelegate.h */, 125 | F48E73BD1977B45700982A46 /* BFPaperAppDelegate.m */, 126 | F48E73BF1977B45700982A46 /* Main.storyboard */, 127 | F48E73C21977B45700982A46 /* BFPaperViewController.h */, 128 | F48E73C31977B45700982A46 /* BFPaperViewController.m */, 129 | F48E73C51977B45700982A46 /* Images.xcassets */, 130 | F48E73B41977B45700982A46 /* Supporting Files */, 131 | ); 132 | path = BFPaperCollectionViewCell; 133 | sourceTree = ""; 134 | }; 135 | F48E73B41977B45700982A46 /* Supporting Files */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | F48E73B51977B45700982A46 /* BFPaperCollectionViewCell-Info.plist */, 139 | F48E73B61977B45700982A46 /* InfoPlist.strings */, 140 | F48E73B91977B45700982A46 /* main.m */, 141 | F48E73BB1977B45700982A46 /* BFPaperCollectionViewCell-Prefix.pch */, 142 | 505849241D5323A100FEE8FE /* Launch Screen.storyboard */, 143 | ); 144 | name = "Supporting Files"; 145 | sourceTree = ""; 146 | }; 147 | F48E73D21977B45700982A46 /* BFPaperCollectionViewCellTests */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | F48E73D31977B45700982A46 /* Supporting Files */, 151 | ); 152 | path = BFPaperCollectionViewCellTests; 153 | sourceTree = ""; 154 | }; 155 | F48E73D31977B45700982A46 /* Supporting Files */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | F48E73D41977B45700982A46 /* BFPaperCollectionViewCellTests-Info.plist */, 159 | F48E73D51977B45700982A46 /* InfoPlist.strings */, 160 | ); 161 | name = "Supporting Files"; 162 | sourceTree = ""; 163 | }; 164 | F48E73E21977BAF000982A46 /* Classes */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | F42B5BA71978DD0000D6F4B5 /* BFPaperCollectionViewCell.h */, 168 | F42B5BA81978DD0000D6F4B5 /* BFPaperCollectionViewCell.m */, 169 | ); 170 | name = Classes; 171 | path = BFPaperCollectionViewCell; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | F48E73A91977B45700982A46 /* BFPaperCollectionViewCell */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = F48E73DC1977B45700982A46 /* Build configuration list for PBXNativeTarget "BFPaperCollectionViewCell" */; 180 | buildPhases = ( 181 | F48E73A61977B45700982A46 /* Sources */, 182 | F48E73A71977B45700982A46 /* Frameworks */, 183 | F4FBB1D31A6C84D800154E09 /* ShellScript */, 184 | F48E73A81977B45700982A46 /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = BFPaperCollectionViewCell; 191 | productName = BFPaperCollectionViewCell; 192 | productReference = F48E73AA1977B45700982A46 /* BFPaperCollectionViewCell.app */; 193 | productType = "com.apple.product-type.application"; 194 | }; 195 | F48E73CA1977B45700982A46 /* BFPaperCollectionViewCellTests */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = F48E73DF1977B45700982A46 /* Build configuration list for PBXNativeTarget "BFPaperCollectionViewCellTests" */; 198 | buildPhases = ( 199 | F48E73C71977B45700982A46 /* Sources */, 200 | F48E73C81977B45700982A46 /* Frameworks */, 201 | F48E73C91977B45700982A46 /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | F48E73D11977B45700982A46 /* PBXTargetDependency */, 207 | ); 208 | name = BFPaperCollectionViewCellTests; 209 | productName = BFPaperCollectionViewCellTests; 210 | productReference = F48E73CB1977B45700982A46 /* BFPaperCollectionViewCellTests.xctest */; 211 | productType = "com.apple.product-type.bundle.unit-test"; 212 | }; 213 | /* End PBXNativeTarget section */ 214 | 215 | /* Begin PBXProject section */ 216 | F48E73A21977B45700982A46 /* Project object */ = { 217 | isa = PBXProject; 218 | attributes = { 219 | CLASSPREFIX = BFPaper; 220 | LastUpgradeCheck = 0730; 221 | ORGANIZATIONNAME = "Bence Feher"; 222 | TargetAttributes = { 223 | F48E73CA1977B45700982A46 = { 224 | TestTargetID = F48E73A91977B45700982A46; 225 | }; 226 | }; 227 | }; 228 | buildConfigurationList = F48E73A51977B45700982A46 /* Build configuration list for PBXProject "BFPaperCollectionViewCell" */; 229 | compatibilityVersion = "Xcode 3.2"; 230 | developmentRegion = English; 231 | hasScannedForEncodings = 0; 232 | knownRegions = ( 233 | en, 234 | Base, 235 | ); 236 | mainGroup = F48E73A11977B45700982A46; 237 | productRefGroup = F48E73AB1977B45700982A46 /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | F48E73A91977B45700982A46 /* BFPaperCollectionViewCell */, 242 | F48E73CA1977B45700982A46 /* BFPaperCollectionViewCellTests */, 243 | ); 244 | }; 245 | /* End PBXProject section */ 246 | 247 | /* Begin PBXResourcesBuildPhase section */ 248 | F48E73A81977B45700982A46 /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | F48E73C61977B45700982A46 /* Images.xcassets in Resources */, 253 | F48E73B81977B45700982A46 /* InfoPlist.strings in Resources */, 254 | 505849251D5323A100FEE8FE /* Launch Screen.storyboard in Resources */, 255 | F48E73C11977B45700982A46 /* Main.storyboard in Resources */, 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | }; 259 | F48E73C91977B45700982A46 /* Resources */ = { 260 | isa = PBXResourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | F48E73D71977B45700982A46 /* InfoPlist.strings in Resources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXResourcesBuildPhase section */ 268 | 269 | /* Begin PBXShellScriptBuildPhase section */ 270 | F4FBB1D31A6C84D800154E09 /* ShellScript */ = { 271 | isa = PBXShellScriptBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | ); 275 | inputPaths = ( 276 | ); 277 | outputPaths = ( 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | shellPath = /bin/bash; 281 | shellScript = "echo \"Running Build Number bash script.\"\nbuildNumber=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"$INFOPLIST_FILE\")\nbuildNumber=$(($buildNumber + 1))\n/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $buildNumber\" \"$INFOPLIST_FILE\"\nupdatedBuildNumber=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"$INFOPLIST_FILE\")\necho \"Updated Build Number $updatedBuildNumber\""; 282 | }; 283 | /* End PBXShellScriptBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | F48E73A61977B45700982A46 /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | F4533CD81A157DA500DF9E50 /* SubclassOfPaperCollectionViewCell.m in Sources */, 291 | F42B5BA91978DD0000D6F4B5 /* BFPaperCollectionViewCell.m in Sources */, 292 | F48E73C41977B45700982A46 /* BFPaperViewController.m in Sources */, 293 | F48E73BA1977B45700982A46 /* main.m in Sources */, 294 | F48E73BE1977B45700982A46 /* BFPaperAppDelegate.m in Sources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | F48E73C71977B45700982A46 /* Sources */ = { 299 | isa = PBXSourcesBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXSourcesBuildPhase section */ 306 | 307 | /* Begin PBXTargetDependency section */ 308 | F48E73D11977B45700982A46 /* PBXTargetDependency */ = { 309 | isa = PBXTargetDependency; 310 | target = F48E73A91977B45700982A46 /* BFPaperCollectionViewCell */; 311 | targetProxy = F48E73D01977B45700982A46 /* PBXContainerItemProxy */; 312 | }; 313 | /* End PBXTargetDependency section */ 314 | 315 | /* Begin PBXVariantGroup section */ 316 | F48E73B61977B45700982A46 /* InfoPlist.strings */ = { 317 | isa = PBXVariantGroup; 318 | children = ( 319 | F48E73B71977B45700982A46 /* en */, 320 | ); 321 | name = InfoPlist.strings; 322 | sourceTree = ""; 323 | }; 324 | F48E73BF1977B45700982A46 /* Main.storyboard */ = { 325 | isa = PBXVariantGroup; 326 | children = ( 327 | F48E73C01977B45700982A46 /* Base */, 328 | ); 329 | name = Main.storyboard; 330 | sourceTree = ""; 331 | }; 332 | F48E73D51977B45700982A46 /* InfoPlist.strings */ = { 333 | isa = PBXVariantGroup; 334 | children = ( 335 | F48E73D61977B45700982A46 /* en */, 336 | ); 337 | name = InfoPlist.strings; 338 | sourceTree = ""; 339 | }; 340 | /* End PBXVariantGroup section */ 341 | 342 | /* Begin XCBuildConfiguration section */ 343 | F48E73DA1977B45700982A46 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ALWAYS_SEARCH_USER_PATHS = NO; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_WARN_BOOL_CONVERSION = YES; 352 | CLANG_WARN_CONSTANT_CONVERSION = YES; 353 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 359 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 360 | COPY_PHASE_STRIP = NO; 361 | ENABLE_TESTABILITY = YES; 362 | GCC_C_LANGUAGE_STANDARD = gnu99; 363 | GCC_DYNAMIC_NO_PIC = NO; 364 | GCC_OPTIMIZATION_LEVEL = 0; 365 | GCC_PREPROCESSOR_DEFINITIONS = ( 366 | "DEBUG=1", 367 | "$(inherited)", 368 | ); 369 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 370 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 371 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 372 | GCC_WARN_UNDECLARED_SELECTOR = YES; 373 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 374 | GCC_WARN_UNUSED_FUNCTION = YES; 375 | GCC_WARN_UNUSED_VARIABLE = YES; 376 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 377 | ONLY_ACTIVE_ARCH = YES; 378 | SDKROOT = iphoneos; 379 | }; 380 | name = Debug; 381 | }; 382 | F48E73DB1977B45700982A46 /* Release */ = { 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_MODULES = YES; 389 | CLANG_ENABLE_OBJC_ARC = YES; 390 | CLANG_WARN_BOOL_CONVERSION = YES; 391 | CLANG_WARN_CONSTANT_CONVERSION = YES; 392 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 393 | CLANG_WARN_EMPTY_BODY = YES; 394 | CLANG_WARN_ENUM_CONVERSION = YES; 395 | CLANG_WARN_INT_CONVERSION = YES; 396 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = YES; 400 | ENABLE_NS_ASSERTIONS = NO; 401 | GCC_C_LANGUAGE_STANDARD = gnu99; 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 409 | SDKROOT = iphoneos; 410 | VALIDATE_PRODUCT = YES; 411 | }; 412 | name = Release; 413 | }; 414 | F48E73DD1977B45700982A46 /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 418 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 419 | GCC_PREFIX_HEADER = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Prefix.pch"; 420 | INFOPLIST_FILE = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Info.plist"; 421 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 422 | PRODUCT_BUNDLE_IDENTIFIER = "com.bencefeher.${PRODUCT_NAME:rfc1034identifier}"; 423 | PRODUCT_NAME = BFPaperCollectionViewCell; 424 | WRAPPER_EXTENSION = app; 425 | }; 426 | name = Debug; 427 | }; 428 | F48E73DE1977B45700982A46 /* Release */ = { 429 | isa = XCBuildConfiguration; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 433 | GCC_PREFIX_HEADER = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Prefix.pch"; 434 | INFOPLIST_FILE = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Info.plist"; 435 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 436 | PRODUCT_BUNDLE_IDENTIFIER = "com.bencefeher.${PRODUCT_NAME:rfc1034identifier}"; 437 | PRODUCT_NAME = BFPaperCollectionViewCell; 438 | WRAPPER_EXTENSION = app; 439 | }; 440 | name = Release; 441 | }; 442 | F48E73E01977B45700982A46 /* Debug */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BFPaperCollectionViewCell.app/BFPaperCollectionViewCell"; 446 | FRAMEWORK_SEARCH_PATHS = ( 447 | "$(SDKROOT)/Developer/Library/Frameworks", 448 | "$(inherited)", 449 | "$(DEVELOPER_FRAMEWORKS_DIR)", 450 | ); 451 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 452 | GCC_PREFIX_HEADER = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Prefix.pch"; 453 | GCC_PREPROCESSOR_DEFINITIONS = ( 454 | "DEBUG=1", 455 | "$(inherited)", 456 | ); 457 | INFOPLIST_FILE = "BFPaperCollectionViewCellTests/BFPaperCollectionViewCellTests-Info.plist"; 458 | PRODUCT_BUNDLE_IDENTIFIER = "com.bencefeher.${PRODUCT_NAME:rfc1034identifier}"; 459 | PRODUCT_NAME = BFPaperCollectionViewCellTests; 460 | TEST_HOST = "$(BUNDLE_LOADER)"; 461 | WRAPPER_EXTENSION = xctest; 462 | }; 463 | name = Debug; 464 | }; 465 | F48E73E11977B45700982A46 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BFPaperCollectionViewCell.app/BFPaperCollectionViewCell"; 469 | FRAMEWORK_SEARCH_PATHS = ( 470 | "$(SDKROOT)/Developer/Library/Frameworks", 471 | "$(inherited)", 472 | "$(DEVELOPER_FRAMEWORKS_DIR)", 473 | ); 474 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 475 | GCC_PREFIX_HEADER = "BFPaperCollectionViewCell/BFPaperCollectionViewCell-Prefix.pch"; 476 | INFOPLIST_FILE = "BFPaperCollectionViewCellTests/BFPaperCollectionViewCellTests-Info.plist"; 477 | PRODUCT_BUNDLE_IDENTIFIER = "com.bencefeher.${PRODUCT_NAME:rfc1034identifier}"; 478 | PRODUCT_NAME = BFPaperCollectionViewCellTests; 479 | TEST_HOST = "$(BUNDLE_LOADER)"; 480 | WRAPPER_EXTENSION = xctest; 481 | }; 482 | name = Release; 483 | }; 484 | /* End XCBuildConfiguration section */ 485 | 486 | /* Begin XCConfigurationList section */ 487 | F48E73A51977B45700982A46 /* Build configuration list for PBXProject "BFPaperCollectionViewCell" */ = { 488 | isa = XCConfigurationList; 489 | buildConfigurations = ( 490 | F48E73DA1977B45700982A46 /* Debug */, 491 | F48E73DB1977B45700982A46 /* Release */, 492 | ); 493 | defaultConfigurationIsVisible = 0; 494 | defaultConfigurationName = Release; 495 | }; 496 | F48E73DC1977B45700982A46 /* Build configuration list for PBXNativeTarget "BFPaperCollectionViewCell" */ = { 497 | isa = XCConfigurationList; 498 | buildConfigurations = ( 499 | F48E73DD1977B45700982A46 /* Debug */, 500 | F48E73DE1977B45700982A46 /* Release */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | F48E73DF1977B45700982A46 /* Build configuration list for PBXNativeTarget "BFPaperCollectionViewCellTests" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | F48E73E01977B45700982A46 /* Debug */, 509 | F48E73E11977B45700982A46 /* Release */, 510 | ); 511 | defaultConfigurationIsVisible = 0; 512 | defaultConfigurationName = Release; 513 | }; 514 | /* End XCConfigurationList section */ 515 | }; 516 | rootObject = F48E73A21977B45700982A46 /* Project object */; 517 | } 518 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperAppDelegate.h 3 | // BFPaperCollectionViewCell 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | #import 34 | 35 | @interface BFPaperAppDelegate : UIResponder 36 | 37 | @property (strong, nonatomic) UIWindow *window; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperAppDelegate.m 3 | // BFPaperCollectionViewCell 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | #import "BFPaperAppDelegate.h" 34 | 35 | @implementation BFPaperAppDelegate 36 | 37 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 38 | { 39 | // Override point for customization after application launch. 40 | return YES; 41 | } 42 | 43 | - (void)applicationWillResignActive:(UIApplication *)application 44 | { 45 | // 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. 46 | // 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. 47 | } 48 | 49 | - (void)applicationDidEnterBackground:(UIApplication *)application 50 | { 51 | // 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. 52 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 53 | } 54 | 55 | - (void)applicationWillEnterForeground:(UIApplication *)application 56 | { 57 | // 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. 58 | } 59 | 60 | - (void)applicationDidBecomeActive:(UIApplication *)application 61 | { 62 | // 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. 63 | } 64 | 65 | - (void)applicationWillTerminate:(UIApplication *)application 66 | { 67 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperCollectionViewCell-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 | 2.3 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 7 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperCollectionViewCell-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_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperViewController.h 3 | // BFPaperCollectionViewCell 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | #import 34 | 35 | @interface BFPaperViewController : UICollectionViewController 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/BFPaperViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperViewController.m 3 | // BFPaperCollectionViewCell 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | /****************************************************/ 34 | /* !!! NOTE !!! */ 35 | /* This file is basically copypasta of */ 36 | /* BFPaperTableViewCell's BFPaperViewController.m. */ 37 | /* There is a lot of code here that isn't used for */ 38 | /* this demo but is used in the */ 39 | /* BFPaperTableViewCell version. Sorry and enjoy. */ 40 | /****************************************************/ 41 | 42 | 43 | #import "BFPaperViewController.h" 44 | // Classes: 45 | #import "SubclassOfPaperCollectionViewCell.h" 46 | 47 | 48 | 49 | @interface BFPaperViewController () 50 | @property NSArray *colors; 51 | @end 52 | 53 | @implementation BFPaperViewController 54 | 55 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 56 | { 57 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 58 | if (self) { 59 | // Custom initialization 60 | } 61 | return self; 62 | } 63 | 64 | - (void)viewDidLoad 65 | { 66 | [super viewDidLoad]; 67 | // Do any additional setup after loading the view. 68 | self.title = @"BFPaperCollectionViewCell"; 69 | 70 | // Register BFPaperCollectionViewCell for our tableView: 71 | [self.collectionView registerClass:[SubclassOfPaperCollectionViewCell class] forCellWithReuseIdentifier:@"BFPaperCell"]; 72 | 73 | // Fill up an array with all the basic BFPaperColors: 74 | self.colors = @[[UIColor colorWithRed:244.f/255.f green:67.f/255.f blue:54.f/255.f alpha:1], 75 | [UIColor colorWithRed:233.f/255.f green:30.f/255.f blue:99.f/255.f alpha:1], 76 | [UIColor colorWithRed:156.f/255.f green:39.f/255.f blue:176.f/255.f alpha:1], 77 | [UIColor colorWithRed:103.f/255.f green:58.f/255.f blue:183.f/255.f alpha:1], 78 | [UIColor colorWithRed:63.f/255.f green:81.f/255.f blue:181.f/255.f alpha:1], 79 | [UIColor colorWithRed:33.f/255.f green:150.f/255.f blue:243.f/255.f alpha:1], 80 | [UIColor colorWithRed:3.f/255.f green:169.f/255.f blue:244.f/255.f alpha:1], 81 | [UIColor colorWithRed:0.f/255.f green:188.f/255.f blue:212.f/255.f alpha:1], 82 | [UIColor colorWithRed:0.f/255.f green:150.f/255.f blue:136.f/255.f alpha:1], 83 | [UIColor colorWithRed:76.f/255.f green:175.f/255.f blue:80.f/255.f alpha:1], 84 | [UIColor colorWithRed:139.f/255.f green:195.f/255.f blue:74.f/255.f alpha:1], 85 | [UIColor colorWithRed:205.f/255.f green:220.f/255.f blue:57.f/255.f alpha:1], 86 | [UIColor colorWithRed:255.f/255.f green:235.f/255.f blue:59.f/255.f alpha:1], 87 | [UIColor colorWithRed:255.f/255.f green:193.f/255.f blue:7.f/255.f alpha:1], 88 | [UIColor colorWithRed:255.f/255.f green:152.f/255.f blue:0.f/255.f alpha:1], 89 | [UIColor colorWithRed:255.f/255.f green:87.f/255.f blue:34.f/255.f alpha:1], 90 | [UIColor colorWithRed:121.f/255.f green:85.f/255.f blue:72.f/255.f alpha:1], 91 | [UIColor colorWithRed:158.f/255.f green:158.f/255.f blue:158.f/255.f alpha:1], 92 | [UIColor colorWithRed:96.f/255.f green:125.f/255.f blue:139.f/255.f alpha:1], 93 | [UIColor colorWithRed:97.f/255.f green:97.f/255.f blue:97.f/255.f alpha:1], 94 | [UIColor colorWithRed:97.f/255.f green:97.f/255.f blue:97.f/255.f alpha:1]]; 95 | 96 | self.collectionView.dataSource = self; 97 | self.collectionView.delegate = self; 98 | 99 | self.collectionView.backgroundColor = [UIColor colorWithRed:0.7 green:0.98 blue:0.7 alpha:1]; 100 | } 101 | 102 | - (void)viewWillAppear:(BOOL)animated 103 | { 104 | [super viewWillAppear:animated]; 105 | 106 | UIImageView *bgIV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg-blue-white-arrow"]]; 107 | bgIV.contentMode = UIViewContentModeScaleAspectFill; 108 | bgIV.frame = self.collectionView.frame; 109 | self.collectionView.backgroundView = bgIV; 110 | } 111 | 112 | - (void)didReceiveMemoryWarning 113 | { 114 | [super didReceiveMemoryWarning]; 115 | // Dispose of any resources that can be recreated. 116 | } 117 | 118 | /* 119 | #pragma mark - Navigation 120 | 121 | // In a storyboard-based application, you will often want to do a little preparation before navigation 122 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 123 | { 124 | // Get the new view controller using [segue destinationViewController]. 125 | // Pass the selected object to the new view controller. 126 | } 127 | */ 128 | 129 | #pragma mark - collection view delegate 130 | //- (void) collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath 131 | //{ 132 | // // Every 5th cell gets to push: 133 | // if (indexPath.row % 5 == 0) { 134 | // [self performSegueWithIdentifier:@"push" sender:self]; 135 | // } 136 | //} 137 | 138 | 139 | #pragma mark - collection view data source 140 | 141 | - (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView 142 | { 143 | // Return the number of sections. 144 | return 1; 145 | } 146 | 147 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 148 | { 149 | // Return the number of rows in the section. 150 | return self.colors.count * 2; // We will have one set of cells with a white background and colored text, and one set with a colored background and white text. 151 | } 152 | 153 | 154 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 155 | { 156 | SubclassOfPaperCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"BFPaperCell" forIndexPath:indexPath]; 157 | 158 | // Configure the cell... 159 | 160 | // This is a whole bunch of really BAD ways to customize cells that I'm, just doing for the demo. 161 | // I hope you won't attempt to customize your cells in such a way and would rather sub-class BFPaperCollectionViewCell and do your customizations in said subclass. 162 | // Or at least just don't do it like this ;p 163 | 164 | // TODO: we should subclass and add a label in the subclass so that we can label the example cells. Commenting out the 165 | // label setup for now. 166 | 167 | // Even indexed cells will ripple from the center while odd ones will ripple from tap location: 168 | if (indexPath.row % 2 == 0) { 169 | cell.rippleFromTapLocation = NO; 170 | //cell.textLabel.text = @"Ripple from Center"; 171 | } 172 | else { 173 | cell.rippleFromTapLocation = YES; 174 | //cell.textLabel.text = @"Ripple from tap location"; 175 | } 176 | 177 | // Demo clear cell: 178 | if (indexPath.row == 0) { 179 | cell.backgroundColor = [UIColor clearColor]; 180 | //cell.textLabel.textColor = [UIColor colorWithRed:198.f/255.f green:255.f/255.f blue:0.f/255.f alpha:1]; 181 | //cell.textLabel.text = @"Clear"; 182 | cell.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterFull; 183 | } 184 | // The rest of the first half should be white with colored text: 185 | else if (indexPath.row < self.colors.count){ 186 | cell.backgroundColor = [UIColor whiteColor]; 187 | //cell.textLabel.textColor = [self.colors objectAtIndex:indexPath.row]; 188 | cell.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterFull; 189 | } 190 | // After that, just color their background and give them white text: 191 | else if (!(indexPath.row > (self.colors.count * 2) - 3)) { 192 | cell.backgroundColor = [self.colors objectAtIndex:indexPath.row % self.colors.count]; 193 | //cell.textLabel.textColor = [UIColor whiteColor]; 194 | cell.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterFull; 195 | } 196 | // Customize last two cells: 197 | else {//if (indexPath.row > (self.colors.count * 2) - 3) { 198 | //cell.textLabel.text = @"Customized!"; 199 | cell.backgroundColor = [UIColor colorWithRed:103.f/255.f green:58.f/255.f blue:183.f/255.f alpha:1]; 200 | //cell.textLabel.textColor = [UIColor colorWithRed:3.f/255.f green:169.f/255.f blue:244.f/255.f alpha:1]; 201 | cell.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterSmall; 202 | cell.tapCircleColor = [UIColor colorWithRed:198.f/255.f green:255.f/255.f blue:0.f/255.f alpha:0.7f]; 203 | cell.backgroundFadeColor = [UIColor whiteColor]; 204 | cell.letBackgroundLinger = NO; 205 | } 206 | 207 | //cell.textLabel.backgroundColor = [UIColor clearColor]; // If it's not clear, the tap circles and fade layers are occluded by this label's background. 208 | 209 | return cell; 210 | } 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/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 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/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 | } -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/Images.xcassets/bg-blue-white-arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "bg-blue-white-arrow.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/Images.xcassets/bg-blue-white-arrow.imageset/bg-blue-white-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bfeher/BFPaperCollectionViewCell/87eacb3499992720628eebfb20cdabc41c7ea7d8/BFPaperCollectionViewCell/Images.xcassets/bg-blue-white-arrow.imageset/bg-blue-white-arrow.png -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/SubclassOfPaperCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SubclassOfPaperCollectionViewCell.h 3 | // BFPaperCollectionViewCell 4 | // 5 | // This is an example of how to subclass BFPaperCollectionViewCell. 6 | // Note that you MUST call [super awakeFromNib] from within awakeFromNib! 7 | // 8 | // Created by Bence Feher on 11/14/14. 9 | // Copyright (c) 2014 Bence Feher. All rights reserved. 10 | // 11 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 12 | // 13 | 14 | #import 15 | #import "BFPaperCollectionViewCell.h" 16 | 17 | @interface SubclassOfPaperCollectionViewCell : BFPaperCollectionViewCell 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/SubclassOfPaperCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubclassOfPaperCollectionViewCell.m 3 | // BFPaperCollectionViewCell 4 | // 5 | // This is an example of how to subclass BFPaperCollectionViewCell. 6 | // Note that you MUST call [super awakeFromNib] from within awakeFromNib! 7 | // 8 | // Created by Bence Feher on 11/14/14. 9 | // Copyright (c) 2014 Bence Feher. All rights reserved. 10 | // 11 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 12 | // 13 | 14 | #import "SubclassOfPaperCollectionViewCell.h" 15 | 16 | 17 | @implementation SubclassOfPaperCollectionViewCell 18 | 19 | - (instancetype)init 20 | { 21 | self = [super init]; 22 | if (self) { 23 | [self customSetup]; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)awakeFromNib 29 | { 30 | // Initialization code 31 | [super awakeFromNib]; // THIS IS NECESSARY! 32 | [self customSetup]; 33 | } 34 | 35 | - (void)prepareForReuse 36 | { 37 | [super prepareForReuse]; 38 | 39 | // This is a good place to call your custom setup function. 40 | [self customSetup]; 41 | } 42 | 43 | - (void)customSetup 44 | { 45 | // Even though defaults values are cool, I'm setting all of the customizable options here as an example: 46 | self.tapCircleColor = [UIColor colorWithRed:198.f/255.f green:255.f/255.f blue:0/255.f alpha:0.6]; 47 | self.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterSmall; 48 | self.rippleFromTapLocation = YES; 49 | self.backgroundFadeColor = [UIColor colorWithWhite:1 alpha:0.2f]; 50 | self.letBackgroundLinger = YES; 51 | 52 | // CGRect maskRect = CGRectMake(5, 5, 10, 10); 53 | // self.maskPath = [UIBezierPath bezierPathWithRoundedRect:maskRect cornerRadius:5.f]; // Just to show this property exists. 54 | 55 | // Other setup (eg. text labels, image views, etc.): 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCell/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // BFPaperCollectionViewCell 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "BFPaperAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([BFPaperAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCellTests/BFPaperCollectionViewCellTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCellTests/BFPaperTableViewCellTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperCollectionViewCellTests.m 3 | // BFPaperCollectionViewCellTests 4 | // 5 | // Created by Bence Feher on 7/17/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BFPaperCollectionViewCellTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation BFPaperCollectionViewCellTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /BFPaperCollectionViewCellTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | BFPaperCollectionViewCell 2 | ==================== 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/BFPaperCollectionViewCell.svg?style=flat)](https://github.com/bfeher/BFPaperCollectionViewCell) 4 | 5 | > Note that this changelog was started very late, at roughly the time between version 2.1.17 and 2.2.2. Non consecutive jumps in changelog mean that there were incremental builds that weren't released as a pod, typically while solving a problem. 6 | 7 | 8 | 9 | 2.3.7 10 | --------- 11 | * (-) Removed all BFPaperColor dependency and code. 12 | * (^) Properties now appear in Interface Builder (IBInspectable)! 13 | * (+) Added launch screen to example project. 14 | 15 | 16 | 2.3.4 17 | --------- 18 | * (+) Migrated to Cocoapods 1.0. 19 | 20 | 21 | 2.3.3 22 | --------- 23 | * (^) Updated pods. 24 | 25 | 26 | 2.3.2 27 | --------- 28 | * (+) Added new property, UIBezierPath *maskPath. 29 | 30 | 31 | 2.2.2 32 | --------- 33 | * (+) Added a changelog! 34 | * (+) Added public property `tapDelay` to allow control over whether or not to spawn a tap circle. If the touch ends or is cancelled before the tap-delay is complete, no circles will be spawned. Default is `0.1f`. 35 | * (+) Applied changes from BFPaperTableViewCell thanks to user @eithanshavit, bringing back support for a tapDelay of 0. 36 | * (-) Removed vestigial private property `letGo`. 37 | * (-) Removed vestigial private property `beganHighlight`. 38 | * (-) Removed vestigial private property `beganSelection`. 39 | * (-) Removed vestigial private property `bAlreadyFadedBackgroundIn`. 40 | * (-) Removed vestigial private property `bAlreadyFadedBackgroundOut`. -------------------------------------------------------------------------------- /Classes/BFPaperCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperCollectionViewCell.h 3 | // BFPaperKit 4 | // 5 | // Created by Bence Feher on 7/11/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | #import 34 | 35 | // Nice circle diameter constants: 36 | extern const CGFloat bfPaperCollectionViewCell_tapCircleDiameterMedium; 37 | extern const CGFloat bfPaperCollectionViewCell_tapCircleDiameterLarge; 38 | extern const CGFloat bfPaperCollectionViewCell_tapCircleDiameterSmall; 39 | extern const CGFloat bfPaperCollectionViewCell_tapCircleDiameterFull; 40 | extern const CGFloat bfPaperCollectionViewCell_tapCircleDiameterDefault; 41 | 42 | IB_DESIGNABLE 43 | @interface BFPaperCollectionViewCell : UICollectionViewCell 44 | 45 | #pragma mark - Properties 46 | #pragma mark Animation 47 | /** A CGFLoat representing the duration of the animations which take place on touch DOWN! Default is 0.25f seconds. (Go Steelers) */ 48 | @property IBInspectable CGFloat touchDownAnimationDuration; 49 | /** A CGFLoat representing the duration of the animations which take place on touch UP! Default is 2 * touchDownAnimationDuration seconds. */ 50 | @property IBInspectable CGFloat touchUpAnimationDuration; 51 | 52 | 53 | #pragma mark Prettyness and Behaviour 54 | /** A CGFLoat representing the diameter of the tap-circle as soon as it spawns, before it grows. Default is 5.f. */ 55 | @property IBInspectable CGFloat tapCircleDiameterStartValue; 56 | 57 | /** The CGFloat value representing the Diameter of the tap-circle. By default it will be the result of MAX(self.frame.width, self.frame.height). tapCircleDiameterFull will calculate a circle that always fills the entire view. Any value less than or equal to tapCircleDiameterFull will result in default being used. The constants: tapCircleDiameterLarge, tapCircleDiameterMedium, and tapCircleDiameterSmall are also available for use. */ 58 | @property IBInspectable CGFloat tapCircleDiameter; 59 | 60 | /** The CGFloat value representing how much we should increase the diameter of the tap-circle by when we burst it. Default is 100.f. */ 61 | @property IBInspectable CGFloat tapCircleBurstAmount; 62 | 63 | /** The UIColor to use for the circle which appears where you tap. NOTE: Setting this defeats the "Smart Color" ability of the tap circle. Alpha values less than 1 are recommended. */ 64 | @property IBInspectable UIColor *tapCircleColor; 65 | 66 | /** The UIColor to fade clear backgrounds to. NOTE: Setting this defeats the "Smart Color" ability of the background fade. Alpha values less than 1 are recommended. */ 67 | @property IBInspectable UIColor *backgroundFadeColor; 68 | 69 | /** A flag to set to YES to have the tap-circle ripple from point of touch. If this is set to NO, the tap-circle will always ripple from the center of the tab. Default is YES. */ 70 | @property (nonatomic) IBInspectable BOOL rippleFromTapLocation; 71 | 72 | /** A BOOL flag that determines whether or not to keep the background around after a tap, essentially "highlighting/selecting" the cell. Note that this does not trigger setSelected:! It is purely aesthetic. Also this kinda clashes with cell.selectionStyle, so by defualt the constructor sets that to UITableViewCellSelectionStyleNone. 73 | Default is YES. */ 74 | @property IBInspectable BOOL letBackgroundLinger; 75 | 76 | /** A BOOL flag indicating whether or not to always complete a full animation cycle (bg fade in, tap-circle grow and burst, bg fade out) before starting another one. NO will behave just like the other BFPaper controls, tapping rapidly spawns many circles which all fade out in turn. Default is YES. */ 77 | @property IBInspectable BOOL alwaysCompleteFullAnimation; 78 | 79 | /** A CGFLoat to set the amount of time in seconds to delay the tap event / trigger to spawn circles. For example, if the tapDelay is set to 1.f, you need to press and hold the cell for 1.f seconds to trigger spawning a circle. Default is 0.1f. */ 80 | @property IBInspectable CGFloat tapDelay; 81 | 82 | /** A UIBezierPath you can set to override the mask path of the ripples and background fade. Set this if you have a custom path for your cell. If this is nil, BFPaperTableViewCell will try its best to provide a correct mask. Default is nil. */ 83 | @property IBInspectable UIBezierPath *maskPath; 84 | @end 85 | -------------------------------------------------------------------------------- /Classes/BFPaperCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // BFPaperCollectionViewCell.m 3 | // BFPaperKit 4 | // 5 | // Created by Bence Feher on 7/11/14. 6 | // Copyright (c) 2014 Bence Feher. All rights reserved. 7 | // 8 | // Converted from BFPaperTableViewCell by Benjamin Truitt https://github.com/benvolioT 9 | // 10 | // The MIT License (MIT) 11 | // 12 | // Copyright (c) 2014 Bence Feher 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | 33 | #import "BFPaperCollectionViewCell.h" 34 | 35 | @interface BFPaperCollectionViewCell () 36 | @property CGRect fadeAndClippingMaskRect; 37 | @property CGPoint tapPoint; 38 | @property CALayer *backgroundColorFadeLayer; 39 | @property BOOL growthFinished; 40 | @property BOOL touchCancelledOrEnded; 41 | @property NSMutableArray *rippleAnimationQueue; 42 | @property NSMutableArray *deathRowForCircleLayers; // This is where old circle layers go to be killed :( 43 | //@property BOOL fadedBackgroundOutAlready; 44 | //@property BOOL fadedBackgroundInAlready; 45 | @property UIColor *dumbTapCircleFillColor; 46 | @property UIColor *dumbBackgroundFadeColor; 47 | @property (nonatomic, copy) void (^removeEffectsQueue)(); 48 | @end 49 | 50 | @implementation BFPaperCollectionViewCell 51 | // Public consts: 52 | CGFloat const bfPaperCollectionViewCell_tapCircleDiameterMedium = 462.f; 53 | CGFloat const bfPaperCollectionViewCell_tapCircleDiameterLarge = bfPaperCollectionViewCell_tapCircleDiameterMedium * 1.4f; 54 | CGFloat const bfPaperCollectionViewCell_tapCircleDiameterSmall = bfPaperCollectionViewCell_tapCircleDiameterMedium / 2.f; 55 | CGFloat const bfPaperCollectionViewCell_tapCircleDiameterFull = -1.f; 56 | CGFloat const bfPaperCollectionViewCell_tapCircleDiameterDefault = -2.f; 57 | 58 | 59 | #pragma mark - Default Initializers 60 | - (id)init 61 | { 62 | self = [super init]; 63 | if (self) { 64 | // Initialization code 65 | [self setupBFPaperCollectionViewCell]; 66 | } 67 | return self; 68 | } 69 | 70 | - (id)initWithCoder:(NSCoder *)aDecoder { 71 | self = [super initWithCoder:aDecoder]; 72 | if (self) { 73 | // Initialization code 74 | [self setupBFPaperCollectionViewCell]; 75 | } 76 | return self; 77 | } 78 | 79 | - (id)initWithFrame:(CGRect)frame { 80 | self = [super initWithFrame:frame]; 81 | if (self) { 82 | // Initialization code 83 | [self setupBFPaperCollectionViewCell]; 84 | } 85 | return self; 86 | } 87 | 88 | - (void)awakeFromNib 89 | { 90 | // Initialization code 91 | [self setupBFPaperCollectionViewCell]; 92 | } 93 | 94 | 95 | #pragma mark - Setup 96 | - (void)setupBFPaperCollectionViewCell 97 | { 98 | // Defaults: 99 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 100 | // Defaults for visual properties: // 101 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 102 | // Animation: 103 | self.touchDownAnimationDuration = 0.2f; 104 | self.touchUpAnimationDuration = self.touchDownAnimationDuration * 2.5f; 105 | // Prettyness and Behaviour: 106 | self.tapCircleColor = nil; 107 | self.backgroundFadeColor = nil; 108 | self.rippleFromTapLocation = YES; 109 | self.tapCircleDiameterStartValue = 5.f; 110 | self.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterDefault; 111 | self.tapCircleBurstAmount = 40.f; 112 | self.dumbTapCircleFillColor = [UIColor colorWithWhite:0.3 alpha:0.25f]; 113 | self.dumbBackgroundFadeColor = [UIColor colorWithWhite:0.3 alpha:0.15f]; 114 | self.letBackgroundLinger = YES; 115 | self.alwaysCompleteFullAnimation = YES; 116 | self.tapDelay = 0.1f; 117 | self.maskPath = nil; 118 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 119 | 120 | self.rippleAnimationQueue = [NSMutableArray array]; 121 | self.deathRowForCircleLayers = [NSMutableArray array]; 122 | 123 | self.layer.masksToBounds = YES; 124 | self.clipsToBounds = YES; 125 | 126 | self.fadeAndClippingMaskRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height); 127 | // Setup background fade layer: 128 | self.backgroundColorFadeLayer = [[CALayer alloc] init]; 129 | self.backgroundColorFadeLayer.frame = self.fadeAndClippingMaskRect; 130 | self.backgroundColorFadeLayer.backgroundColor = [UIColor clearColor].CGColor; 131 | self.backgroundColorFadeLayer.opacity = 0; 132 | [self.contentView.layer insertSublayer:self.backgroundColorFadeLayer atIndex:0]; 133 | 134 | UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:nil]; 135 | tapGestureRecognizer.delegate = self; 136 | [self addGestureRecognizer:tapGestureRecognizer]; 137 | } 138 | 139 | 140 | #pragma Parent Overides 141 | - (void)setSelected:(BOOL)selected 142 | { 143 | [super setSelected:selected]; 144 | //NSLog(@"setSelected:\'%@\', selected ? @"YES" : @"NO"); 145 | 146 | if (!self.letBackgroundLinger) { 147 | return; // If we are not letting the background linger, just return as we have nothing more to do here. 148 | } 149 | 150 | if (!selected) { 151 | [self removeBackground]; 152 | } 153 | else { 154 | [self fadeBackgroundIn]; 155 | } 156 | } 157 | 158 | /* 159 | - (void)prepareForReuse 160 | { 161 | [super prepareForReuse]; 162 | 163 | // Lets go ahead and "reset" our cell: 164 | // In your subclass, this is where you would call your custom setup. 165 | [self setupBFPaperCollectionViewCell]; 166 | } 167 | */ 168 | 169 | - (void)layoutSubviews 170 | { 171 | [super layoutSubviews]; 172 | 173 | self.fadeAndClippingMaskRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y , self.bounds.size.width, self.bounds.size.height); 174 | self.backgroundColorFadeLayer.frame = self.fadeAndClippingMaskRect; 175 | 176 | [self setNeedsDisplay]; 177 | [self.layer setNeedsDisplay]; 178 | } 179 | 180 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 181 | { 182 | [super touchesBegan:touches withEvent:event]; 183 | 184 | self.touchCancelledOrEnded = NO; 185 | self.growthFinished = NO; 186 | 187 | if (self.tapDelay > 0) { 188 | // Dispatch on main thread to delay animations 189 | dispatch_main_after(self.tapDelay, ^{ 190 | if (!self.touchCancelledOrEnded) { 191 | [self fadeBackgroundIn]; 192 | [self growTapCircle]; 193 | } 194 | else { 195 | [self setSelected:NO]; 196 | [self fadeBGOut]; 197 | } 198 | }); 199 | 200 | } 201 | else { 202 | // Avoid dispatching if there's no delay 203 | [self fadeBackgroundIn]; 204 | [self growTapCircle]; 205 | } 206 | } 207 | 208 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 209 | { 210 | [super touchesEnded:touches withEvent:event]; 211 | 212 | self.touchCancelledOrEnded = YES; 213 | 214 | [self removeCircle]; 215 | if (!self.letBackgroundLinger) { 216 | [self removeBackground]; 217 | } 218 | } 219 | 220 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 221 | { 222 | [super touchesCancelled:touches withEvent:event]; 223 | 224 | self.touchCancelledOrEnded = YES; 225 | 226 | [self removeCircle]; 227 | [self removeBackground]; 228 | } 229 | 230 | 231 | #pragma mark - Gesture Recognizer Delegate 232 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { 233 | 234 | CGPoint location = [touch locationInView:self]; 235 | //NSLog(@"location: x = %0.2f, y = %0.2f", location.x, location.y); 236 | self.tapPoint = location; 237 | 238 | return NO; // Disallow recognition of tap gestures. We just needed this to grab that tasty tap location. 239 | } 240 | 241 | 242 | #pragma mark - Animation: 243 | - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag 244 | { 245 | //NSLog(@"animation ENDED"); 246 | self.growthFinished = YES; 247 | 248 | if ([[animation valueForKey:@"id"] isEqualToString:@"fadeCircleOut"]) { 249 | [[self.deathRowForCircleLayers objectAtIndex:0] removeFromSuperlayer]; 250 | if (self.deathRowForCircleLayers.count > 0) { 251 | [self.deathRowForCircleLayers removeObjectAtIndex:0]; 252 | } 253 | } 254 | 255 | if (self.alwaysCompleteFullAnimation) { 256 | if (self.removeEffectsQueue) { 257 | self.removeEffectsQueue(); 258 | self.removeEffectsQueue = nil; 259 | } 260 | } 261 | } 262 | 263 | - (void)removeCircle 264 | { 265 | if (!self.alwaysCompleteFullAnimation) { 266 | [self burstTapCircle]; 267 | } 268 | else { 269 | ////////////////////////////////////////////////////////////////////////////// 270 | // Special thanks to github user @ThePantsThief for providing this code! // 271 | ////////////////////////////////////////////////////////////////////////////// 272 | if (self.growthFinished) { 273 | [self burstTapCircle]; 274 | } else { 275 | void (^oldCompletion)() = self.removeEffectsQueue; 276 | __weak typeof(self) weakSelf = self; 277 | 278 | self.removeEffectsQueue = ^void() { 279 | if (oldCompletion) 280 | oldCompletion(); 281 | [weakSelf burstTapCircle]; 282 | }; 283 | } 284 | } 285 | } 286 | 287 | - (void)removeBackground 288 | { 289 | if (!self.alwaysCompleteFullAnimation) { 290 | [self fadeBGOut]; 291 | } 292 | else { 293 | ////////////////////////////////////////////////////////////////////////////// 294 | // Special thanks to github user @ThePantsThief for providing this code! // 295 | ////////////////////////////////////////////////////////////////////////////// 296 | if (self.growthFinished) { 297 | [self fadeBGOut]; 298 | } else { 299 | void (^oldCompletion)() = self.removeEffectsQueue; 300 | __weak typeof(self) weakSelf = self; 301 | self.removeEffectsQueue = ^void() { 302 | if (oldCompletion) 303 | oldCompletion(); 304 | [weakSelf fadeBGOut]; 305 | }; 306 | } 307 | } 308 | } 309 | 310 | - (void)fadeBackgroundIn 311 | { 312 | if (!self.backgroundFadeColor) { 313 | self.backgroundFadeColor = self.dumbBackgroundFadeColor; 314 | } 315 | 316 | if (nil != self.maskPath) { 317 | CAShapeLayer *mask = [CAShapeLayer layer]; 318 | mask.path = self.maskPath.CGPath; 319 | mask.fillColor = [UIColor blackColor].CGColor; 320 | mask.strokeColor = [UIColor clearColor].CGColor; 321 | mask.borderColor = [UIColor clearColor].CGColor; 322 | mask.borderWidth = 0; 323 | self.backgroundColorFadeLayer.mask = mask; 324 | } 325 | 326 | // Setup background fade layer: 327 | self.backgroundColorFadeLayer.backgroundColor = self.backgroundFadeColor.CGColor; 328 | 329 | CGFloat startingOpacity = self.backgroundColorFadeLayer.opacity; 330 | 331 | if ([[self.backgroundColorFadeLayer animationKeys] count] > 0) { 332 | startingOpacity = [[self.backgroundColorFadeLayer presentationLayer] opacity]; 333 | } 334 | 335 | // Fade the background color a bit darker: 336 | CABasicAnimation *fadeBackgroundDarker = [CABasicAnimation animationWithKeyPath:@"opacity"]; 337 | fadeBackgroundDarker.duration = self.touchDownAnimationDuration; 338 | fadeBackgroundDarker.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 339 | fadeBackgroundDarker.fromValue = [NSNumber numberWithFloat:startingOpacity]; 340 | fadeBackgroundDarker.toValue = [NSNumber numberWithFloat:1]; 341 | fadeBackgroundDarker.fillMode = kCAFillModeForwards; 342 | fadeBackgroundDarker.removedOnCompletion = !NO; 343 | self.backgroundColorFadeLayer.opacity = 1; 344 | 345 | [self.backgroundColorFadeLayer addAnimation:fadeBackgroundDarker forKey:@"animateOpacity"]; 346 | } 347 | 348 | - (void)growTapCircle 349 | { 350 | //NSLog(@"expanding a tap circle"); 351 | // Spawn a growing circle that "ripples" through the button: 352 | 353 | // Set the fill color for the tap circle (self.animationLayer's fill color): 354 | if (!self.tapCircleColor) { 355 | self.tapCircleColor = self.dumbTapCircleFillColor; 356 | } 357 | 358 | // Calculate the tap circle's ending diameter: 359 | CGFloat tapCircleFinalDiameter = [self calculateTapCircleFinalDiameter]; 360 | 361 | // Create a UIView which we can modify for its frame value later (specifically, the ability to use .center): 362 | UIView *tapCircleLayerSizerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tapCircleFinalDiameter, tapCircleFinalDiameter)]; 363 | tapCircleLayerSizerView.center = self.rippleFromTapLocation ? self.tapPoint : CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); 364 | 365 | // Calculate starting path: 366 | UIView *startingRectSizerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tapCircleDiameterStartValue, self.tapCircleDiameterStartValue)]; 367 | startingRectSizerView.center = tapCircleLayerSizerView.center; 368 | 369 | // Create starting circle path: 370 | UIBezierPath *startingCirclePath = [UIBezierPath bezierPathWithRoundedRect:startingRectSizerView.frame cornerRadius:self.tapCircleDiameterStartValue / 2.f]; 371 | 372 | // Calculate ending path: 373 | UIView *endingRectSizerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tapCircleFinalDiameter, tapCircleFinalDiameter)]; 374 | endingRectSizerView.center = tapCircleLayerSizerView.center; 375 | 376 | // Create ending circle path: 377 | UIBezierPath *endingCirclePath = [UIBezierPath bezierPathWithRoundedRect:endingRectSizerView.frame cornerRadius:tapCircleFinalDiameter / 2.f]; 378 | 379 | // Create tap circle: 380 | CAShapeLayer *tapCircle = [CAShapeLayer layer]; 381 | tapCircle.fillColor = self.tapCircleColor.CGColor; 382 | tapCircle.strokeColor = [UIColor clearColor].CGColor; 383 | tapCircle.borderColor = [UIColor clearColor].CGColor; 384 | tapCircle.borderWidth = 0; 385 | tapCircle.path = startingCirclePath.CGPath; 386 | 387 | // Create a mask if we are not going to ripple over bounds: 388 | CAShapeLayer *mask = [CAShapeLayer layer]; 389 | mask.path = (nil == self.maskPath) ? [UIBezierPath bezierPathWithRoundedRect:self.fadeAndClippingMaskRect cornerRadius:self.layer.cornerRadius].CGPath : self.maskPath.CGPath; 390 | mask.fillColor = [UIColor blackColor].CGColor; 391 | mask.strokeColor = [UIColor clearColor].CGColor; 392 | mask.borderColor = [UIColor clearColor].CGColor; 393 | mask.borderWidth = 0; 394 | 395 | // Set tap circle layer's mask to the mask: 396 | tapCircle.mask = mask; 397 | 398 | // Add tap circle to array and view: 399 | [self.rippleAnimationQueue addObject:tapCircle]; 400 | [self.contentView.layer insertSublayer:tapCircle above:self.backgroundColorFadeLayer]; 401 | 402 | 403 | // Grow tap-circle animation (performed on mask layer): 404 | CABasicAnimation *tapCircleGrowthAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; 405 | tapCircleGrowthAnimation.delegate = self; 406 | tapCircleGrowthAnimation.duration = self.touchDownAnimationDuration; 407 | tapCircleGrowthAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 408 | tapCircleGrowthAnimation.fromValue = (__bridge id)startingCirclePath.CGPath; 409 | tapCircleGrowthAnimation.toValue = (__bridge id)endingCirclePath.CGPath; 410 | tapCircleGrowthAnimation.fillMode = kCAFillModeForwards; 411 | tapCircleGrowthAnimation.removedOnCompletion = NO; 412 | 413 | // Fade in self.animationLayer: 414 | CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:@"opacity"]; 415 | fadeIn.duration = self.touchDownAnimationDuration; 416 | fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 417 | fadeIn.fromValue = [NSNumber numberWithFloat:0.f]; 418 | fadeIn.toValue = [NSNumber numberWithFloat:1.f]; 419 | fadeIn.fillMode = kCAFillModeForwards; 420 | fadeIn.removedOnCompletion = NO; 421 | 422 | // Add the animations to the layers: 423 | [tapCircle addAnimation:tapCircleGrowthAnimation forKey:@"animatePath"]; 424 | [tapCircle addAnimation:fadeIn forKey:@"opacityAnimation"]; 425 | } 426 | 427 | - (void)fadeBGOut 428 | { 429 | //NSLog(@"fading bg"); 430 | 431 | CGFloat startingOpacity = self.backgroundColorFadeLayer.opacity; 432 | 433 | // Grab the current value if we are currently animating: 434 | if ([[self.backgroundColorFadeLayer animationKeys] count] > 0) { 435 | startingOpacity = [[self.backgroundColorFadeLayer presentationLayer] opacity]; 436 | } 437 | 438 | CABasicAnimation *removeFadeBackgroundDarker = [CABasicAnimation animationWithKeyPath:@"opacity"]; 439 | removeFadeBackgroundDarker.duration = self.touchUpAnimationDuration; 440 | removeFadeBackgroundDarker.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 441 | removeFadeBackgroundDarker.fromValue = [NSNumber numberWithFloat:startingOpacity]; 442 | removeFadeBackgroundDarker.toValue = [NSNumber numberWithFloat:0]; 443 | removeFadeBackgroundDarker.fillMode = kCAFillModeForwards; 444 | removeFadeBackgroundDarker.removedOnCompletion = !NO; 445 | self.backgroundColorFadeLayer.opacity = 0; 446 | 447 | [self.backgroundColorFadeLayer addAnimation:removeFadeBackgroundDarker forKey:@"animateOpacity"]; 448 | } 449 | 450 | - (void)burstTapCircle 451 | { 452 | //NSLog(@"expanding a bit more"); 453 | 454 | if (1 > self.rippleAnimationQueue.count) { 455 | return; // We don't have any circles to burst, we can just leave and ponder how and why we got here in this state. 456 | } 457 | 458 | // Get the next tap circle to expand: 459 | CAShapeLayer *tapCircle = [self.rippleAnimationQueue firstObject]; 460 | if (self.rippleAnimationQueue.count > 0) { 461 | [self.rippleAnimationQueue removeObjectAtIndex:0]; 462 | } 463 | [self.deathRowForCircleLayers addObject:tapCircle]; 464 | 465 | 466 | // Calculate the tap circle's ending diameter: 467 | CGFloat tapCircleFinalDiameter = [self calculateTapCircleFinalDiameter]; 468 | tapCircleFinalDiameter += self.tapCircleBurstAmount; 469 | 470 | UIView *endingRectSizerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tapCircleFinalDiameter, tapCircleFinalDiameter)]; 471 | endingRectSizerView.center = self.rippleFromTapLocation ? self.tapPoint : CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); 472 | 473 | // Create ending circle path for mask: 474 | UIBezierPath *endingCirclePath = [UIBezierPath bezierPathWithRoundedRect:endingRectSizerView.frame cornerRadius:tapCircleFinalDiameter / 2.f]; 475 | 476 | 477 | CGPathRef startingPath = tapCircle.path; 478 | CGFloat startingOpacity = tapCircle.opacity; 479 | 480 | if ([[tapCircle animationKeys] count] > 0) { 481 | startingPath = [[tapCircle presentationLayer] path]; 482 | startingOpacity = [[tapCircle presentationLayer] opacity]; 483 | } 484 | 485 | // Burst tap-circle: 486 | CABasicAnimation *tapCircleGrowthAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; 487 | tapCircleGrowthAnimation.duration = self.touchUpAnimationDuration; 488 | tapCircleGrowthAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 489 | tapCircleGrowthAnimation.fromValue = (__bridge id)startingPath; 490 | tapCircleGrowthAnimation.toValue = (__bridge id)endingCirclePath.CGPath; 491 | tapCircleGrowthAnimation.fillMode = kCAFillModeForwards; 492 | tapCircleGrowthAnimation.removedOnCompletion = NO; 493 | 494 | // Fade tap-circle out: 495 | CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"]; 496 | [fadeOut setValue:@"fadeCircleOut" forKey:@"id"]; 497 | fadeOut.delegate = self; 498 | fadeOut.fromValue = [NSNumber numberWithFloat:startingOpacity]; 499 | fadeOut.toValue = [NSNumber numberWithFloat:0.f]; 500 | fadeOut.duration = self.touchUpAnimationDuration; 501 | fadeOut.fillMode = kCAFillModeForwards; 502 | fadeOut.removedOnCompletion = NO; 503 | 504 | [tapCircle addAnimation:tapCircleGrowthAnimation forKey:@"animatePath"]; 505 | [tapCircle addAnimation:fadeOut forKey:@"opacityAnimation"]; 506 | } 507 | 508 | - (CGFloat)calculateTapCircleFinalDiameter 509 | { 510 | CGFloat finalDiameter = self.tapCircleDiameter; 511 | if (self.tapCircleDiameter == bfPaperCollectionViewCell_tapCircleDiameterFull) { 512 | // Calulate a diameter that will always cover the entire button: 513 | ////////////////////////////////////////////////////////////////////////////// 514 | // Special thanks to github user @ThePantsThief for providing this code! // 515 | ////////////////////////////////////////////////////////////////////////////// 516 | CGFloat centerWidth = self.frame.size.width; 517 | CGFloat centerHeight = self.frame.size.height; 518 | CGFloat tapWidth = 2 * MAX(self.tapPoint.x, centerWidth - self.tapPoint.x); 519 | CGFloat tapHeight = 2 * MAX(self.tapPoint.y, centerHeight - self.tapPoint.y); 520 | CGFloat desiredWidth = self.rippleFromTapLocation ? tapWidth : centerWidth; 521 | CGFloat desiredHeight = self.rippleFromTapLocation ? tapHeight : centerHeight; 522 | CGFloat diameter = sqrt(pow(desiredWidth, 2) + pow(desiredHeight, 2)); 523 | finalDiameter = diameter; 524 | } 525 | else if (self.tapCircleDiameter < bfPaperCollectionViewCell_tapCircleDiameterFull) { // default 526 | finalDiameter = MAX(self.frame.size.width, self.frame.size.height); 527 | } 528 | return finalDiameter; 529 | } 530 | 531 | 532 | #pragma mark - Helpers 533 | static void dispatch_main_after(NSTimeInterval delay, void (^block)(void)) 534 | { 535 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 536 | block(); 537 | }); 538 | } 539 | #pragma mark - 540 | 541 | 542 | @end 543 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © (c) 2015 Bence Feher 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BFPaperCollectionViewCell 2 | ==================== 3 | [![CocoaPods](https://img.shields.io/cocoapods/v/BFPaperCollectionViewCell.svg?style=flat)](https://github.com/bfeher/BFPaperCollectionViewCell) 4 | 5 | > A subclass of UICollectionViewCell inspired by Google's Material Design: Paper Elements. Based on [BFPaperTableViewCell](https://github.com/bfeher/BFPaperTableViewCell), written by [Benjamin Truitt](https://github.com/benvolioT) 6 | 7 | About 8 | --------- 9 | ### Now with smoother animations and more public properties for even easier customization! 10 | 11 | _BFPaperCollectionViewCell_ is a subclass of UICollectionViewCell that behaves much like the new paper cells from Google's Material Design Labs. 12 | All animation are asynchronous and are performed on sublayers. 13 | _BFPaperCollectionViewCells_ work right away with pleasing default behaviors, however they can be easily customized! The tap-circle color, background fade color, background fade alpha, background highlight (linger or fade away), tap-circle ripple locaiton, and tap-circle diameter are all readily customizable via public properties. 14 | 15 | ## Properties 16 | `CGFloat touchDownAnimationDuration` 17 | > A CGFLoat representing the duration of the animations which take place on touch DOWN! Default is `0.25f` seconds. (Go Steelers) 18 | 19 | `CGFloat touchUpAnimationDuration` 20 | > A CGFLoat representing the duration of the animations which take place on touch UP! Default is `2 * touchDownAnimationDuration` seconds. 21 | 22 | `CGFloat tapCircleDiameterStartValue` 23 | > A CGFLoat representing the diameter of the tap-circle as soon as it spawns, before it grows. Default is `5.f`. 24 | 25 | `CGFloat tapCircleDiameter` 26 | > The CGFloat value representing the Diameter of the tap-circle. By default it will be the result of `MAX(self.frame.width, self.frame.height)`. `tapCircleDiameterFull` will calculate a circle that always fills the entire view. Any value less than or equal to `tapCircleDiameterFull` will result in default being used. The constants: `tapCircleDiameterLarge`, `tapCircleDiameterMedium`, and `tapCircleDiameterSmall` are also available for use. 27 | 28 | `CGFloat tapCircleBurstAmount` 29 | > The CGFloat value representing how much we should increase the diameter of the tap-circle by when we burst it. Default is `40.f`. 30 | 31 | `UIColor *tapCircleColor` 32 | > The UIColor to use for the circle which appears where you tap. NOTE: Setting this defeats the "Smart Color" ability of the tap circle. Alpha values less than `1` are recommended. 33 | 34 | `UIColor *backgroundFadeColor` 35 | > The UIColor to fade clear backgrounds to. NOTE: Setting this defeats the "Smart Color" ability of the background fade. Alpha values less than `1` are recommended. 36 | 37 | `BOOL rippleFromTapLocation` 38 | > A flag to set to `YES` to have the tap-circle ripple from point of touch. If this is set to `NO`, the tap-circle will always ripple from the center of the view. Default is `YES`. 39 | 40 | `BOOL letBackgroundLinger` 41 | > A BOOL flag that determines whether or not to keep the background around after a tap, essentially "highlighting/selecting" the cell. Note that this does not trigger `setSelected:`! It is purely aesthetic. Also this kinda clashes with `cell.selectionStyle`, so by defualt the constructor sets that to `UITableViewCellSelectionStyleNone`. Default is YES. 42 | 43 | `BOOL alwaysCompleteFullAnimation` 44 | > A BOOL flag indicating whether or not to always complete a full animation cycle (bg fade in, tap-circle grow and burst, bg fade out) before starting another one. NO will behave just like the other BFPaper controls, tapping rapidly spawns many circles which all fade out in turn. Default is `YES`. 45 | 46 | `CGFloat tapDelay` 47 | > A CGFLoat to set the amount of time in seconds to delay the tap event / trigger to spawn circles. For example, if the tapDelay is set to `1.f`, you need to press and hold the cell for 1 second to trigger spawning a circle. Default is `0.1f`. 48 | 49 | `UIBezierPath *maskPath` 50 | > A UIBezierPath you can set to override the mask path of the ripples and background fade. Set this if you have a custom path for your cell. If this is `nil`, BFPaperTableViewCell will try its best to provide a correct mask. Default is `nil`. 51 | 52 | 53 | Usage 54 | --------- 55 | Add the _BFPaperCollectionViewCell_ header and implementation file to your project. (.h & .m) 56 | 57 | After that, you can use it just like any other `UICollectionViewCell`. 58 | 59 | If you use storyboards with prototype cells, be sure to change the prototype cell's class to _BFPaperCollectionViewCell_, and be sure to set the reuse identifier to that with which you register in the below code snippet! 60 | 61 | ###Example 62 | ```objective-c 63 | // Register BFPaperCollectionViewCell for our collectionView in viewDidLoad: 64 | - (void)viewDidLoad 65 | { 66 | ... 67 | [self.collectionView registerClass:[BFPaperCollectionViewCell class] forCellWithReuseIdentifier:@"BFPaperCell"]; 68 | ... 69 | } 70 | 71 | 72 | - (UICollectionViewCell *)tableView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 73 | { 74 | BFPaperCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"BFPaperCell" forIndexPath:indexPath]; 75 | 76 | cell.rippleFromTapLocation = NO; // Will always ripple from center if NO. 77 | cell.tapCircleColor = [[UIColor paperColorDeepPurple] colorWithAlphaComponent:0.3f]; // Paper Colors can be found in my BFPaperColors library :) 78 | cell.backgroundFadeColor = [UIColor paperColorBlue]; // Paper Colors can be found in my BFPaperColors library :) 79 | cell.backgroundFadeAlpha = 0.7f; 80 | cell.letBackgroundLinger = NO; 81 | cell.tapCircleDiameter = bfPaperCollectionViewCell_tapCircleDiameterSmall; 82 | return cell; 83 | } 84 | ``` 85 | 86 | 87 | CocoaPods 88 | ------- 89 | 90 | CocoaPods are the best way to manage library dependencies in Objective-C projects. 91 | Learn more at http://cocoapods.org 92 | 93 | Add this to your podfile to add _BFPaperCollectionViewCell_ to your project. 94 | ```ruby 95 | platform :ios, '7.1' 96 | pod 'BFPaperCollectionViewCell' 97 | ``` 98 | 99 | 100 | License 101 | -------- 102 | _BFPaperCollectionViewCell_ uses the MIT License: 103 | 104 | > Please see included LICENSE file. 105 | --------------------------------------------------------------------------------