├── .gitignore ├── .travis.yml ├── Example ├── Podfile ├── gooey-cell.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── gooey-cell-Example.xcscheme ├── gooey-cell.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── gooey-cell │ ├── AppDelegate.swift │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Fonts │ ├── Butler-Medium.otf │ ├── SF-UI-Text-Bold.otf │ └── SF-UI-Text-Regular.otf │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon_60@2x.png │ │ ├── Icon_60@3x.png │ │ ├── Icon_76.png │ │ ├── Icon_76@2x.png │ │ └── Icon_83@2x.png │ ├── Contents.json │ ├── cuberto-logo.imageset │ │ ├── Contents.json │ │ ├── cuberto-logo.png │ │ ├── cuberto-logo@2x.png │ │ └── cuberto-logo@3x.png │ ├── icon1.imageset │ │ ├── Contents.json │ │ ├── icon1.png │ │ ├── icon1@2x.png │ │ └── icon1@3x.png │ ├── icon2.imageset │ │ ├── Contents.json │ │ ├── icon2.png │ │ ├── icon2@2x.png │ │ └── icon2@3x.png │ ├── icon3.imageset │ │ ├── Contents.json │ │ ├── icon3.png │ │ ├── icon3@2x.png │ │ └── icon3@3x.png │ ├── icon4.imageset │ │ ├── Contents.json │ │ ├── icon4.png │ │ ├── icon4@2x.png │ │ └── icon4@3x.png │ ├── icon5.imageset │ │ ├── Contents.json │ │ ├── icon5.png │ │ ├── icon5@2x.png │ │ └── icon5@3x.png │ ├── image_cross.imageset │ │ ├── Contents.json │ │ ├── image_cross.png │ │ ├── image_cross@2x.png │ │ └── image_cross@3x.png │ ├── image_mark.imageset │ │ ├── Contents.json │ │ ├── image_mark.png │ │ ├── image_mark@2x.png │ │ └── image_mark@3x.png │ └── imgSearch.imageset │ │ ├── Contents.json │ │ ├── imgSearch.png │ │ ├── imgSearch@2x.png │ │ └── imgSearch@3x.png │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── TableViewCell.swift │ ├── TableViewController.swift │ └── ViewController.swift ├── LICENSE ├── README.md ├── Screenshots └── animation.gif ├── _Pods.xcodeproj ├── gooey-cell.podspec └── gooey-cell ├── Assets └── .gitkeep └── Classes ├── .gitkeep ├── GooeyEffect.swift └── GooeyEffectTableViewCell.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | Example/Pods 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | # Package.resolved 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots/**/*.png 69 | fastlane/test_output 70 | Podfile.lock 71 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/gooey-cell.xcworkspace -scheme gooey-cell-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'gooey-cell_Example' do 4 | pod 'gooey-cell', :path => '../' 5 | end 6 | -------------------------------------------------------------------------------- /Example/gooey-cell.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D71D9DE0F0499EDE6CC240B /* Pods_gooey_cell_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AE7C58684629DE5D480454F5 /* Pods_gooey_cell_Example.framework */; }; 11 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 12 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; }; 13 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; 14 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 15 | 941A59CA21FA2EEB0006418D /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A59C821FA2EEB0006418D /* TableViewController.swift */; }; 16 | 941A59CB21FA2EEB0006418D /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 941A59C921FA2EEB0006418D /* TableViewCell.swift */; }; 17 | 941A59D221FA2F0D0006418D /* Butler-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = 941A59CF21FA2F0C0006418D /* Butler-Medium.otf */; }; 18 | 941A59D621FA30AB0006418D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 941A59D521FA30AB0006418D /* LaunchScreen.storyboard */; }; 19 | 9437A1F421FB666A00492A13 /* SF-UI-Text-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9437A1F221FB653500492A13 /* SF-UI-Text-Bold.otf */; }; 20 | 9437A1F521FB666A00492A13 /* SF-UI-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9437A1F321FB653500492A13 /* SF-UI-Text-Regular.otf */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | 3508ED8AE79B951620514DEB /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 25 | 3D21F0440FC3035EB1EAADBF /* Pods-gooey-cell_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-gooey-cell_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-gooey-cell_Tests/Pods-gooey-cell_Tests.debug.xcconfig"; sourceTree = ""; }; 26 | 607FACD01AFB9204008FA782 /* gooey-cell_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "gooey-cell_Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 28 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 30 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 31 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 32 | 6A73769D23354E696C1BB083 /* gooey-cell.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = "gooey-cell.podspec"; path = "../gooey-cell.podspec"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 33 | 76F9FF4F523335584837D21E /* Pods-gooey-cell_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-gooey-cell_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-gooey-cell_Example/Pods-gooey-cell_Example.release.xcconfig"; sourceTree = ""; }; 34 | 864E96828FB210D65F1712AE /* Pods-gooey-cell_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-gooey-cell_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-gooey-cell_Example/Pods-gooey-cell_Example.debug.xcconfig"; sourceTree = ""; }; 35 | 941A59C821FA2EEB0006418D /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; 36 | 941A59C921FA2EEB0006418D /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; 37 | 941A59CF21FA2F0C0006418D /* Butler-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Butler-Medium.otf"; sourceTree = ""; }; 38 | 941A59D521FA30AB0006418D /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 39 | 9437A1F221FB653500492A13 /* SF-UI-Text-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Bold.otf"; sourceTree = ""; }; 40 | 9437A1F321FB653500492A13 /* SF-UI-Text-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Regular.otf"; sourceTree = ""; }; 41 | AE7C58684629DE5D480454F5 /* Pods_gooey_cell_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_gooey_cell_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | B115A511A4D4C3189AE11C50 /* Pods_gooey_cell_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_gooey_cell_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | C5FC659980785DBBFE2E6502 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 44 | D7C60FA55F66C5673770807D /* Pods-gooey-cell_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-gooey-cell_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-gooey-cell_Tests/Pods-gooey-cell_Tests.release.xcconfig"; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 607FACCD1AFB9204008FA782 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | 1D71D9DE0F0499EDE6CC240B /* Pods_gooey_cell_Example.framework in Frameworks */, 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | 1CECFE3B504F759DDCFF7256 /* Pods */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 864E96828FB210D65F1712AE /* Pods-gooey-cell_Example.debug.xcconfig */, 63 | 76F9FF4F523335584837D21E /* Pods-gooey-cell_Example.release.xcconfig */, 64 | 3D21F0440FC3035EB1EAADBF /* Pods-gooey-cell_Tests.debug.xcconfig */, 65 | D7C60FA55F66C5673770807D /* Pods-gooey-cell_Tests.release.xcconfig */, 66 | ); 67 | name = Pods; 68 | sourceTree = ""; 69 | }; 70 | 607FACC71AFB9204008FA782 = { 71 | isa = PBXGroup; 72 | children = ( 73 | 607FACF51AFB993E008FA782 /* Podspec Metadata */, 74 | 607FACD21AFB9204008FA782 /* Example for gooey-cell */, 75 | 607FACD11AFB9204008FA782 /* Products */, 76 | 1CECFE3B504F759DDCFF7256 /* Pods */, 77 | 87C57BD22112ACE784B32F40 /* Frameworks */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | 607FACD11AFB9204008FA782 /* Products */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 607FACD01AFB9204008FA782 /* gooey-cell_Example.app */, 85 | ); 86 | name = Products; 87 | sourceTree = ""; 88 | }; 89 | 607FACD21AFB9204008FA782 /* Example for gooey-cell */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */, 93 | 607FACD71AFB9204008FA782 /* ViewController.swift */, 94 | 941A59C921FA2EEB0006418D /* TableViewCell.swift */, 95 | 941A59C821FA2EEB0006418D /* TableViewController.swift */, 96 | 607FACD91AFB9204008FA782 /* Main.storyboard */, 97 | 941A59D521FA30AB0006418D /* LaunchScreen.storyboard */, 98 | 607FACDC1AFB9204008FA782 /* Images.xcassets */, 99 | 941A59CC21FA2F0C0006418D /* Fonts */, 100 | 607FACD31AFB9204008FA782 /* Supporting Files */, 101 | ); 102 | name = "Example for gooey-cell"; 103 | path = "gooey-cell"; 104 | sourceTree = ""; 105 | }; 106 | 607FACD31AFB9204008FA782 /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 607FACD41AFB9204008FA782 /* Info.plist */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 6A73769D23354E696C1BB083 /* gooey-cell.podspec */, 118 | C5FC659980785DBBFE2E6502 /* README.md */, 119 | 3508ED8AE79B951620514DEB /* LICENSE */, 120 | ); 121 | name = "Podspec Metadata"; 122 | sourceTree = ""; 123 | }; 124 | 87C57BD22112ACE784B32F40 /* Frameworks */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | AE7C58684629DE5D480454F5 /* Pods_gooey_cell_Example.framework */, 128 | B115A511A4D4C3189AE11C50 /* Pods_gooey_cell_Tests.framework */, 129 | ); 130 | name = Frameworks; 131 | sourceTree = ""; 132 | }; 133 | 941A59CC21FA2F0C0006418D /* Fonts */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 941A59CF21FA2F0C0006418D /* Butler-Medium.otf */, 137 | 9437A1F221FB653500492A13 /* SF-UI-Text-Bold.otf */, 138 | 9437A1F321FB653500492A13 /* SF-UI-Text-Regular.otf */, 139 | ); 140 | path = Fonts; 141 | sourceTree = ""; 142 | }; 143 | /* End PBXGroup section */ 144 | 145 | /* Begin PBXNativeTarget section */ 146 | 607FACCF1AFB9204008FA782 /* gooey-cell_Example */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "gooey-cell_Example" */; 149 | buildPhases = ( 150 | 16197EB4670684621D165C54 /* [CP] Check Pods Manifest.lock */, 151 | 607FACCC1AFB9204008FA782 /* Sources */, 152 | 607FACCD1AFB9204008FA782 /* Frameworks */, 153 | 607FACCE1AFB9204008FA782 /* Resources */, 154 | C0D10CFA258DD7E977C85B9D /* [CP] Embed Pods Frameworks */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = "gooey-cell_Example"; 161 | productName = "gooey-cell"; 162 | productReference = 607FACD01AFB9204008FA782 /* gooey-cell_Example.app */; 163 | productType = "com.apple.product-type.application"; 164 | }; 165 | /* End PBXNativeTarget section */ 166 | 167 | /* Begin PBXProject section */ 168 | 607FACC81AFB9204008FA782 /* Project object */ = { 169 | isa = PBXProject; 170 | attributes = { 171 | LastSwiftUpdateCheck = 0830; 172 | LastUpgradeCheck = 1010; 173 | ORGANIZATIONNAME = CocoaPods; 174 | TargetAttributes = { 175 | 607FACCF1AFB9204008FA782 = { 176 | CreatedOnToolsVersion = 6.3.1; 177 | DevelopmentTeam = SK7A63GXF6; 178 | LastSwiftMigration = 1010; 179 | ProvisioningStyle = Manual; 180 | }; 181 | }; 182 | }; 183 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "gooey-cell" */; 184 | compatibilityVersion = "Xcode 3.2"; 185 | developmentRegion = English; 186 | hasScannedForEncodings = 0; 187 | knownRegions = ( 188 | en, 189 | Base, 190 | ); 191 | mainGroup = 607FACC71AFB9204008FA782; 192 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 193 | projectDirPath = ""; 194 | projectRoot = ""; 195 | targets = ( 196 | 607FACCF1AFB9204008FA782 /* gooey-cell_Example */, 197 | ); 198 | }; 199 | /* End PBXProject section */ 200 | 201 | /* Begin PBXResourcesBuildPhase section */ 202 | 607FACCE1AFB9204008FA782 /* Resources */ = { 203 | isa = PBXResourcesBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | 9437A1F421FB666A00492A13 /* SF-UI-Text-Bold.otf in Resources */, 207 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 208 | 9437A1F521FB666A00492A13 /* SF-UI-Text-Regular.otf in Resources */, 209 | 941A59D221FA2F0D0006418D /* Butler-Medium.otf in Resources */, 210 | 941A59D621FA30AB0006418D /* LaunchScreen.storyboard in Resources */, 211 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, 212 | ); 213 | runOnlyForDeploymentPostprocessing = 0; 214 | }; 215 | /* End PBXResourcesBuildPhase section */ 216 | 217 | /* Begin PBXShellScriptBuildPhase section */ 218 | 16197EB4670684621D165C54 /* [CP] Check Pods Manifest.lock */ = { 219 | isa = PBXShellScriptBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | ); 223 | inputFileListPaths = ( 224 | ); 225 | inputPaths = ( 226 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 227 | "${PODS_ROOT}/Manifest.lock", 228 | ); 229 | name = "[CP] Check Pods Manifest.lock"; 230 | outputFileListPaths = ( 231 | ); 232 | outputPaths = ( 233 | "$(DERIVED_FILE_DIR)/Pods-gooey-cell_Example-checkManifestLockResult.txt", 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | shellPath = /bin/sh; 237 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 238 | showEnvVarsInLog = 0; 239 | }; 240 | C0D10CFA258DD7E977C85B9D /* [CP] Embed Pods Frameworks */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputFileListPaths = ( 246 | ); 247 | inputPaths = ( 248 | "${SRCROOT}/Pods/Target Support Files/Pods-gooey-cell_Example/Pods-gooey-cell_Example-frameworks.sh", 249 | "${BUILT_PRODUCTS_DIR}/gooey-cell/gooey_cell.framework", 250 | "${BUILT_PRODUCTS_DIR}/pop/pop.framework", 251 | ); 252 | name = "[CP] Embed Pods Frameworks"; 253 | outputFileListPaths = ( 254 | ); 255 | outputPaths = ( 256 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/gooey_cell.framework", 257 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pop.framework", 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | shellPath = /bin/sh; 261 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-gooey-cell_Example/Pods-gooey-cell_Example-frameworks.sh\"\n"; 262 | showEnvVarsInLog = 0; 263 | }; 264 | /* End PBXShellScriptBuildPhase section */ 265 | 266 | /* Begin PBXSourcesBuildPhase section */ 267 | 607FACCC1AFB9204008FA782 /* Sources */ = { 268 | isa = PBXSourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */, 272 | 941A59CB21FA2EEB0006418D /* TableViewCell.swift in Sources */, 273 | 941A59CA21FA2EEB0006418D /* TableViewController.swift in Sources */, 274 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | /* End PBXSourcesBuildPhase section */ 279 | 280 | /* Begin PBXVariantGroup section */ 281 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = { 282 | isa = PBXVariantGroup; 283 | children = ( 284 | 607FACDA1AFB9204008FA782 /* Base */, 285 | ); 286 | name = Main.storyboard; 287 | sourceTree = ""; 288 | }; 289 | /* End PBXVariantGroup section */ 290 | 291 | /* Begin XCBuildConfiguration section */ 292 | 607FACED1AFB9204008FA782 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ALWAYS_SEARCH_USER_PATHS = NO; 296 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 297 | CLANG_CXX_LIBRARY = "libc++"; 298 | CLANG_ENABLE_MODULES = YES; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 301 | CLANG_WARN_BOOL_CONVERSION = YES; 302 | CLANG_WARN_COMMA = YES; 303 | CLANG_WARN_CONSTANT_CONVERSION = YES; 304 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 305 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 306 | CLANG_WARN_EMPTY_BODY = YES; 307 | CLANG_WARN_ENUM_CONVERSION = YES; 308 | CLANG_WARN_INFINITE_RECURSION = YES; 309 | CLANG_WARN_INT_CONVERSION = YES; 310 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 311 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 312 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 314 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 315 | CLANG_WARN_STRICT_PROTOTYPES = YES; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 320 | COPY_PHASE_STRIP = NO; 321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 322 | ENABLE_STRICT_OBJC_MSGSEND = YES; 323 | ENABLE_TESTABILITY = YES; 324 | GCC_C_LANGUAGE_STANDARD = gnu99; 325 | GCC_DYNAMIC_NO_PIC = NO; 326 | GCC_NO_COMMON_BLOCKS = YES; 327 | GCC_OPTIMIZATION_LEVEL = 0; 328 | GCC_PREPROCESSOR_DEFINITIONS = ( 329 | "DEBUG=1", 330 | "$(inherited)", 331 | ); 332 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 340 | MTL_ENABLE_DEBUG_INFO = YES; 341 | ONLY_ACTIVE_ARCH = YES; 342 | SDKROOT = iphoneos; 343 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 344 | SWIFT_VERSION = 4.2; 345 | }; 346 | name = Debug; 347 | }; 348 | 607FACEE1AFB9204008FA782 /* Release */ = { 349 | isa = XCBuildConfiguration; 350 | buildSettings = { 351 | ALWAYS_SEARCH_USER_PATHS = NO; 352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 353 | CLANG_CXX_LIBRARY = "libc++"; 354 | CLANG_ENABLE_MODULES = YES; 355 | CLANG_ENABLE_OBJC_ARC = YES; 356 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 357 | CLANG_WARN_BOOL_CONVERSION = YES; 358 | CLANG_WARN_COMMA = YES; 359 | CLANG_WARN_CONSTANT_CONVERSION = YES; 360 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 367 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 368 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 369 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 370 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 371 | CLANG_WARN_STRICT_PROTOTYPES = YES; 372 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 373 | CLANG_WARN_UNREACHABLE_CODE = YES; 374 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 375 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 376 | COPY_PHASE_STRIP = NO; 377 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 378 | ENABLE_NS_ASSERTIONS = NO; 379 | ENABLE_STRICT_OBJC_MSGSEND = YES; 380 | GCC_C_LANGUAGE_STANDARD = gnu99; 381 | GCC_NO_COMMON_BLOCKS = YES; 382 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 383 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 384 | GCC_WARN_UNDECLARED_SELECTOR = YES; 385 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 386 | GCC_WARN_UNUSED_FUNCTION = YES; 387 | GCC_WARN_UNUSED_VARIABLE = YES; 388 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 389 | MTL_ENABLE_DEBUG_INFO = NO; 390 | SDKROOT = iphoneos; 391 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 392 | SWIFT_VERSION = 4.2; 393 | VALIDATE_PRODUCT = YES; 394 | }; 395 | name = Release; 396 | }; 397 | 607FACF01AFB9204008FA782 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | baseConfigurationReference = 864E96828FB210D65F1712AE /* Pods-gooey-cell_Example.debug.xcconfig */; 400 | buildSettings = { 401 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 402 | CODE_SIGN_STYLE = Manual; 403 | DEVELOPMENT_TEAM = SK7A63GXF6; 404 | INFOPLIST_FILE = "gooey-cell/Info.plist"; 405 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 406 | MODULE_NAME = ExampleApp; 407 | PRODUCT_BUNDLE_IDENTIFIER = com.cuberto.components.gooeycell; 408 | PRODUCT_NAME = "$(TARGET_NAME)"; 409 | PROVISIONING_PROFILE_SPECIFIER = CubertoComponents; 410 | SWIFT_VERSION = 4.2; 411 | }; 412 | name = Debug; 413 | }; 414 | 607FACF11AFB9204008FA782 /* Release */ = { 415 | isa = XCBuildConfiguration; 416 | baseConfigurationReference = 76F9FF4F523335584837D21E /* Pods-gooey-cell_Example.release.xcconfig */; 417 | buildSettings = { 418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 419 | CODE_SIGN_STYLE = Manual; 420 | DEVELOPMENT_TEAM = SK7A63GXF6; 421 | INFOPLIST_FILE = "gooey-cell/Info.plist"; 422 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 423 | MODULE_NAME = ExampleApp; 424 | PRODUCT_BUNDLE_IDENTIFIER = com.cuberto.components.gooeycell; 425 | PRODUCT_NAME = "$(TARGET_NAME)"; 426 | PROVISIONING_PROFILE_SPECIFIER = CubertoComponents; 427 | SWIFT_VERSION = 4.2; 428 | }; 429 | name = Release; 430 | }; 431 | /* End XCBuildConfiguration section */ 432 | 433 | /* Begin XCConfigurationList section */ 434 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "gooey-cell" */ = { 435 | isa = XCConfigurationList; 436 | buildConfigurations = ( 437 | 607FACED1AFB9204008FA782 /* Debug */, 438 | 607FACEE1AFB9204008FA782 /* Release */, 439 | ); 440 | defaultConfigurationIsVisible = 0; 441 | defaultConfigurationName = Release; 442 | }; 443 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "gooey-cell_Example" */ = { 444 | isa = XCConfigurationList; 445 | buildConfigurations = ( 446 | 607FACF01AFB9204008FA782 /* Debug */, 447 | 607FACF11AFB9204008FA782 /* Release */, 448 | ); 449 | defaultConfigurationIsVisible = 0; 450 | defaultConfigurationName = Release; 451 | }; 452 | /* End XCConfigurationList section */ 453 | }; 454 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 455 | } 456 | -------------------------------------------------------------------------------- /Example/gooey-cell.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/gooey-cell.xcodeproj/xcshareddata/xcschemes/gooey-cell-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Example/gooey-cell.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/gooey-cell.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/gooey-cell/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 01/24/2019. 6 | // Copyright (c) 2019 Прегер Глеб. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // 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. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // 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. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/gooey-cell/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Example/gooey-cell/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Butler-Medium 15 | 16 | 17 | SFUIText-Bold 18 | 19 | 20 | SFUIText-Regular 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 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 95 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 184 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | -------------------------------------------------------------------------------- /Example/gooey-cell/Fonts/Butler-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Fonts/Butler-Medium.otf -------------------------------------------------------------------------------- /Example/gooey-cell/Fonts/SF-UI-Text-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Fonts/SF-UI-Text-Bold.otf -------------------------------------------------------------------------------- /Example/gooey-cell/Fonts/SF-UI-Text-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Fonts/SF-UI-Text-Regular.otf -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon_60@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "Icon_60@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "ipad", 47 | "size" : "20x20", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "idiom" : "ipad", 52 | "size" : "20x20", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "idiom" : "ipad", 57 | "size" : "29x29", 58 | "scale" : "1x" 59 | }, 60 | { 61 | "idiom" : "ipad", 62 | "size" : "29x29", 63 | "scale" : "2x" 64 | }, 65 | { 66 | "idiom" : "ipad", 67 | "size" : "40x40", 68 | "scale" : "1x" 69 | }, 70 | { 71 | "idiom" : "ipad", 72 | "size" : "40x40", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "76x76", 77 | "idiom" : "ipad", 78 | "filename" : "Icon_76.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "76x76", 83 | "idiom" : "ipad", 84 | "filename" : "Icon_76@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "83.5x83.5", 89 | "idiom" : "ipad", 90 | "filename" : "Icon_83@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "idiom" : "ios-marketing", 95 | "size" : "1024x1024", 96 | "scale" : "1x" 97 | } 98 | ], 99 | "info" : { 100 | "version" : 1, 101 | "author" : "xcode" 102 | } 103 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_60@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_60@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_76.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_76@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_83@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/AppIcon.appiconset/Icon_83@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "cuberto-logo.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "cuberto-logo@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "cuberto-logo@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/cuberto-logo.imageset/cuberto-logo@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon1@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon1@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon1.imageset/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon1.imageset/icon1.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon1.imageset/icon1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon1.imageset/icon1@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon1.imageset/icon1@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon1.imageset/icon1@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon2@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon2@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon2.imageset/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon2.imageset/icon2.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon2.imageset/icon2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon2.imageset/icon2@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon2.imageset/icon2@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon2.imageset/icon2@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon3.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon3@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon3@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon3.imageset/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon3.imageset/icon3.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon3.imageset/icon3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon3.imageset/icon3@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon3.imageset/icon3@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon3.imageset/icon3@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon4.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon4@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon4@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon4.imageset/icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon4.imageset/icon4.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon4.imageset/icon4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon4.imageset/icon4@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon4.imageset/icon4@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon4.imageset/icon4@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon5.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon5@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon5@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon5.imageset/icon5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon5.imageset/icon5.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon5.imageset/icon5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon5.imageset/icon5@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/icon5.imageset/icon5@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/icon5.imageset/icon5@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_cross.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image_cross.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "image_cross@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "image_cross@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_cross.imageset/image_cross@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_mark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image_mark.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "image_mark@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "image_mark@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/image_mark.imageset/image_mark@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/imgSearch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "imgSearch.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "imgSearch@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "imgSearch@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch@2x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Example/gooey-cell/Images.xcassets/imgSearch.imageset/imgSearch@3x.png -------------------------------------------------------------------------------- /Example/gooey-cell/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Gooey Cell 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIAppFonts 30 | 31 | Butler-Medium.otf 32 | SF-UI-Text-Bold.otf 33 | SF-UI-Text-Regular.otf 34 | 35 | UIMainStoryboardFile 36 | Main 37 | UIRequiredDeviceCapabilities 38 | 39 | armv7 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/gooey-cell/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Example/gooey-cell/TableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewCell.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 24/01/2019. 6 | // Copyright © 2019 Cuberto. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import gooey_cell 11 | 12 | class TableViewCell: GooeyEffectTableViewCell { 13 | @IBOutlet var backgroundFrameView: UIView! { 14 | didSet { 15 | backgroundFrameView.layer.shadowColor = UIColor.black.cgColor 16 | backgroundFrameView.layer.shadowRadius = 5 17 | backgroundFrameView.layer.shadowOpacity = 0.08 18 | } 19 | } 20 | @IBOutlet var imgIcon: UIImageView! 21 | @IBOutlet var lblName: UILabel! 22 | @IBOutlet var lblTitle: UILabel! 23 | @IBOutlet var lblDescription: UILabel! 24 | @IBOutlet var lblTime: UILabel! 25 | } 26 | 27 | private extension UIColor { 28 | static func random() -> UIColor { 29 | return UIColor(red: randomCGFloat(), 30 | green: randomCGFloat(), 31 | blue: randomCGFloat(), 32 | alpha: 1.0) 33 | } 34 | 35 | private static func randomCGFloat() -> CGFloat { 36 | return CGFloat(arc4random()) / CGFloat(UInt32.max) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/gooey-cell/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 22/01/2019. 6 | // Copyright © 2019 Cuberto. All rights reserved. 7 | // 8 | import UIKit 9 | import gooey_cell 10 | 11 | class TableViewController: UIViewController { 12 | 13 | @IBOutlet private weak var tableView: UITableView! { 14 | didSet { 15 | tableView.dataSource = self 16 | } 17 | } 18 | 19 | private var objects: [Object] = [] 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | addCells() 25 | } 26 | 27 | @IBAction private func btnSearchTapped(_ sender: UIButton) { 28 | addCells() 29 | } 30 | 31 | private func addCells() { 32 | objects += Object.allCases 33 | tableView.reloadData() 34 | } 35 | } 36 | 37 | extension TableViewController: UITableViewDataSource { 38 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 39 | return objects.count 40 | } 41 | 42 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 43 | 44 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 45 | if let cell = cell as? TableViewCell { 46 | 47 | let object = objects[indexPath.row] 48 | 49 | cell.imgIcon.image = object.icon 50 | cell.lblName.text = object.name 51 | cell.lblTitle.text = object.title 52 | cell.lblDescription.text = object.description 53 | cell.lblTime.text = object.time 54 | 55 | cell.gooeyCellDelegate = self 56 | } 57 | 58 | return cell 59 | } 60 | } 61 | 62 | extension TableViewController: GooeyCellDelegate { 63 | func gooeyCellActionConfig(for cell: UITableViewCell, direction: GooeyEffect.Direction) -> GooeyEffectTableViewCell.ActionConfig? { 64 | let color = #colorLiteral(red: 0.3019607843, green: 0.4980392157, blue: 0.3921568627, alpha: 1) 65 | let image = direction == .toLeft ? #imageLiteral(resourceName: "image_cross") : #imageLiteral(resourceName: "image_mark") 66 | let isCellDeletingAction = direction == .toLeft 67 | 68 | let effectConfig = GooeyEffect.Config(color: color,image: image) 69 | 70 | let actionConfig = GooeyEffectTableViewCell.ActionConfig(effectConfig: effectConfig, 71 | isCellDeletingAction: isCellDeletingAction) 72 | return actionConfig 73 | } 74 | 75 | func gooeyCellActionTriggered(for cell: UITableViewCell, direction: GooeyEffect.Direction) { 76 | switch direction { 77 | case .toLeft: 78 | removeCell(cell) 79 | case .toRight: 80 | break 81 | } 82 | } 83 | 84 | private func removeCell(_ cell: UITableViewCell) { 85 | guard let indexPath = tableView.indexPath(for: cell) else { return } 86 | objects.remove(at: indexPath.row) 87 | tableView.beginUpdates() 88 | tableView.deleteRows(at: [indexPath], with: .fade) 89 | tableView.endUpdates() 90 | } 91 | } 92 | 93 | private extension TableViewController { 94 | enum Object: CaseIterable { 95 | case tripAdvisor, figma, productHuntDaily, invision, pinterest 96 | 97 | var icon: UIImage { 98 | switch self { 99 | case .tripAdvisor: return #imageLiteral(resourceName: "icon4") 100 | case .figma: return #imageLiteral(resourceName: "icon5") 101 | case .productHuntDaily: return #imageLiteral(resourceName: "icon1") 102 | case .invision: return #imageLiteral(resourceName: "icon2") 103 | case .pinterest: return #imageLiteral(resourceName: "icon3") 104 | } 105 | } 106 | 107 | var name: String { 108 | switch self { 109 | case .tripAdvisor: return "TripAdvisor" 110 | case .figma: return "Figma" 111 | case .productHuntDaily: return "Product Hunt Daily" 112 | case .invision: return "invision" 113 | case .pinterest: return "Pinterest" 114 | } 115 | } 116 | 117 | var title: String { 118 | switch self { 119 | case .tripAdvisor: return "Your saved search to Vienna" 120 | case .figma: return "Figma @mentions are here!" 121 | case .productHuntDaily: return "Must-have Chrome Extensions" 122 | case .invision: return "First interview with a designer i admire :)" 123 | case .pinterest: return "You’ve got 18 new ideas waiting for you!" 124 | } 125 | } 126 | 127 | var description: String { 128 | switch self { 129 | case .tripAdvisor: return "Sed ut perspiciatis unde omnis iste…" 130 | case .figma: return "We forgot to give you your Valentin…" 131 | case .productHuntDaily: return "There’s a Chrome extensions for everyth…" 132 | case .invision: return "Hey guys, so I asked on instagram a cou…" 133 | case .pinterest: return "Football Transfer Window by Signal…" 134 | } 135 | } 136 | 137 | var time: String { 138 | switch self { 139 | case .tripAdvisor: return "20 FEB" 140 | case .figma: return "22 FEB" 141 | case .productHuntDaily: return "13:46" 142 | case .invision: return "15:12" 143 | case .pinterest: return "18:30" 144 | } 145 | } 146 | } 147 | } 148 | 149 | -------------------------------------------------------------------------------- /Example/gooey-cell/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 17/01/2019. 6 | // Copyright © 2019 Cuberto. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import gooey_cell 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet private weak var containerView: UIView! 15 | @IBOutlet private weak var horizontalSlider: UISlider! 16 | @IBOutlet private weak var lblProgress: UILabel! 17 | 18 | private var effect: GooeyEffect? 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | let config = GooeyEffect.Config(color: UIColor.red, image: #imageLiteral(resourceName: "imgCross")) 23 | effect = GooeyEffect(to: containerView, verticalPosition: 0.2, direction: .toRight, config: config) 24 | updateEffect() 25 | } 26 | 27 | @IBAction private func sliderValueChanged(_ slider: UISlider) { 28 | updateEffect() 29 | } 30 | 31 | private func updateEffect() { 32 | lblProgress.text = "\(horizontalSlider.value)" 33 | effect?.updateProgress(progress: horizontalSlider.value) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Cuberto Design 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cuberto's development lab: 2 | 3 | Cuberto is a leading digital agency with solid design and development expertise. We build mobile and web products for startups. Drop us a line. 4 | 5 | # gooey-cell 6 | 7 | [![GitHub license](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://raw.githubusercontent.com/Cuberto/gooey-cell/master/LICENSE) 8 | [![CocoaPods](https://img.shields.io/badge/pod-v0.1.0-orange.svg)](http://cocoapods.org/pods/gooey-cell) 9 | [![Swift 4.2](https://img.shields.io/badge/Swift-4.2-green.svg?style=flat)](https://developer.apple.com/swift/) 10 | 11 | 12 | ![Animation](https://raw.githubusercontent.com/Cuberto/gooey-cell/master/Screenshots/animation.gif) 13 | 14 | ## Example 15 | 16 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 17 | 18 | ## Requirements 19 | 20 | - iOS 9.3+ 21 | - Xcode 10 22 | 23 | ## Installation 24 | 25 | gooey-cell is available through [CocoaPods](https://cocoapods.org). To install 26 | it, simply add the following line to your Podfile: 27 | 28 | ```ruby 29 | pod 'gooey-cell' 30 | ``` 31 | Then run `pod install`. 32 | 33 | ## Usage 34 | 35 | 36 | 37 | ## Author 38 | 39 | Cuberto Design, info@cuberto.com 40 | 41 | ## License 42 | 43 | gooey-cell is available under the MIT license. See the LICENSE file for more info. 44 | -------------------------------------------------------------------------------- /Screenshots/animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/Screenshots/animation.gif -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /gooey-cell.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint gooey-cell.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'gooey-cell' 11 | s.version = '0.1.0' 12 | s.summary = 'UITableVIewCell with gooey effect animation' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | TODO: Add long description of the pod here. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/Cuberto/gooey-cell' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'Прегер Глеб' => 'gleb.preger@cuberto.ru' } 28 | s.source = { :git => 'https://github.com/Cuberto/gooey-cell.git', :tag => s.version.to_s } 29 | s.social_media_url = 'https://twitter.com/cuberto' 30 | 31 | s.ios.deployment_target = '9.3' 32 | s.swift_version = '4.2' 33 | s.source_files = 'gooey-cell/Classes/**/*' 34 | 35 | # s.resource_bundles = { 36 | # 'gooey-cell' => ['gooey-cell/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | s.dependency 'pop', '~> 1.0' 42 | end 43 | -------------------------------------------------------------------------------- /gooey-cell/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/gooey-cell/Assets/.gitkeep -------------------------------------------------------------------------------- /gooey-cell/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cuberto/gooey-cell/c10372e2fcf1ee55654187eb0afbe3c5bf2eb605/gooey-cell/Classes/.gitkeep -------------------------------------------------------------------------------- /gooey-cell/Classes/GooeyEffect.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GooeyEffect.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 22/01/2019. 6 | // Copyright © 2019 Cuberto. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import pop 11 | 12 | public class GooeyEffect { 13 | public enum Direction { 14 | case toRight, toLeft 15 | } 16 | 17 | public struct Config { 18 | let color: UIColor? 19 | let image: UIImage? 20 | 21 | public init(color: UIColor?, image: UIImage?) { 22 | self.color = color 23 | self.image = image 24 | } 25 | } 26 | 27 | private struct SnapshotLayerInfo { 28 | let position: CGPoint 29 | let opacity: Float 30 | } 31 | 32 | private struct CircleLayerInfo { 33 | let centerPoint: CGPoint 34 | let radius: CGFloat 35 | let leftPoint: CGPoint 36 | let rightPoint: CGPoint 37 | let path: CGPath? 38 | } 39 | 40 | private struct EdgeLayerInfo { 41 | let topPoint: CGPoint 42 | let topControlPoint: CGPoint 43 | let bottomPoint: CGPoint 44 | let bottomControlPoint: CGPoint 45 | let rightControlPoint: CGPoint 46 | let path: CGPath? 47 | } 48 | 49 | private struct JointLayerInfo { 50 | let path: CGPath? 51 | } 52 | 53 | private struct ImageLayerInfo { 54 | let position: CGPoint 55 | let opacity: Float 56 | let transform: CATransform3D 57 | } 58 | 59 | let direction: Direction 60 | let effectMaxWidth: CGFloat = 170 61 | let gapProgressValue: Float = 0.7 62 | 63 | private let edgeShapeWidthRate: CGFloat = 0.35 64 | private let effectMaxHeight: CGFloat = 150 65 | private let circleShapeRadius: CGFloat = 20 66 | private let jointShapeConstringencyRate: Float = 2 67 | private let fullAnimationDuration: CFTimeInterval = 0.35 68 | private let color: UIColor 69 | private let buttonImage: UIImage? 70 | 71 | private weak var container: UIView? 72 | private let effectCenterY: CGFloat 73 | private let effectHeight: CGFloat 74 | 75 | private let maskLayer = CALayer() 76 | private let snapshotLayer = CALayer() 77 | private let circleLayer = CAShapeLayer() 78 | private let edgeLayer = CAShapeLayer() 79 | private let jointLayer = CAShapeLayer() 80 | private let imageLayer = CALayer() 81 | 82 | private var currentProgress: Float = 0 83 | 84 | public init(to container: UIView, verticalPosition: Float, direction: Direction, config: Config? = nil) { 85 | 86 | var effectCenterY = container.bounds.height * CGFloat(verticalPosition) 87 | effectCenterY = max(circleShapeRadius, min(effectCenterY, (container.bounds.height - circleShapeRadius))) 88 | 89 | self.container = container 90 | self.direction = direction 91 | self.effectCenterY = effectCenterY 92 | self.effectHeight = min(min(effectCenterY, (container.bounds.height - effectCenterY)) * 2, effectMaxHeight) 93 | self.buttonImage = config?.image 94 | self.color = config?.color ?? .clear 95 | 96 | let snapShot = UIImage(view: container) 97 | 98 | var superView: UIView? = container 99 | var maskColor: UIColor? = nil 100 | 101 | repeat { 102 | if let color = superView?.backgroundColor, 103 | color != .clear { 104 | maskColor = color 105 | } else { 106 | superView = superView?.superview 107 | } 108 | } while maskColor == nil && superView != nil 109 | 110 | maskLayer.backgroundColor = (maskColor ?? .white).cgColor 111 | maskLayer.frame = container.layer.bounds 112 | container.layer.addSublayer(maskLayer) 113 | 114 | snapshotLayer.contents = snapShot.cgImage 115 | snapshotLayer.frame = container.layer.bounds 116 | snapshotLayer.actions = ["position": NSNull(), "opacity": NSNull()] 117 | container.layer.addSublayer(snapshotLayer) 118 | 119 | circleLayer.fillColor = color.cgColor 120 | circleLayer.frame = container.layer.bounds 121 | container.layer.addSublayer(circleLayer) 122 | 123 | edgeLayer.fillColor = color.cgColor 124 | edgeLayer.frame = container.layer.bounds 125 | container.layer.addSublayer(edgeLayer) 126 | 127 | jointLayer.fillColor = color.cgColor 128 | jointLayer.frame = container.layer.bounds 129 | container.layer.addSublayer(jointLayer) 130 | 131 | imageLayer.contents = buttonImage?.cgImage 132 | imageLayer.bounds.size = buttonImage?.size ?? .zero 133 | imageLayer.actions = ["position": NSNull(), "opacity": NSNull(), "transform": NSNull()] 134 | container.layer.addSublayer(imageLayer) 135 | 136 | if direction == .toLeft { 137 | container.layer.sublayerTransform = CATransform3DMakeScale(-1, 1, 1) 138 | snapshotLayer.transform = CATransform3DMakeScale(-1, 1, 1) 139 | } 140 | 141 | updateProgress(progress: 0) 142 | } 143 | 144 | deinit { 145 | removeEffect(animated: false) 146 | } 147 | 148 | public func animateToProgress(_ finalProgress: Float, completion: (()->Void)? = nil) { 149 | 150 | let animationStartTime = CACurrentMediaTime() 151 | let startProgress = currentProgress 152 | let progressLength = startProgress - finalProgress 153 | let duration: CFTimeInterval = fullAnimationDuration * CFTimeInterval(abs(progressLength)) 154 | 155 | let animation = POPCustomAnimation { [weak self] (target, animation) -> Bool in 156 | 157 | guard let self = self, 158 | let animation = animation else { 159 | return false 160 | } 161 | 162 | let currentTime = animation.currentTime - animationStartTime 163 | let animationProgress = Float(currentTime / duration) 164 | let progress = startProgress - progressLength * animationProgress 165 | 166 | if progress >= 0 && progress <= 1 { 167 | self.updateProgress(progress: progress) 168 | return true 169 | } else { 170 | self.updateProgress(progress: finalProgress) 171 | return false 172 | } 173 | } 174 | 175 | animation?.completionBlock = {(animation, isFinished) in 176 | completion?() 177 | } 178 | 179 | container?.pop_add(animation, forKey: "animation") 180 | } 181 | 182 | public func removeEffect(animated: Bool, completion: (()->Void)? = nil) { 183 | 184 | snapshotLayer.removeFromSuperlayer() 185 | circleLayer.removeFromSuperlayer() 186 | edgeLayer.removeFromSuperlayer() 187 | jointLayer.removeFromSuperlayer() 188 | imageLayer.removeFromSuperlayer() 189 | 190 | if direction == .toLeft { 191 | container?.layer.sublayerTransform = CATransform3DIdentity 192 | } 193 | 194 | if animated { 195 | CATransaction.begin() 196 | let animation = CABasicAnimation(keyPath: "opacity") 197 | animation.isRemovedOnCompletion = false 198 | animation.fillMode = .forwards 199 | animation.toValue = 0 200 | animation.duration = fullAnimationDuration 201 | CATransaction.setCompletionBlock { [weak self] in 202 | self?.maskLayer.removeFromSuperlayer() 203 | completion?() 204 | } 205 | maskLayer.add(animation, forKey: "opacity") 206 | CATransaction.commit() 207 | } else { 208 | maskLayer.removeFromSuperlayer() 209 | } 210 | } 211 | 212 | public func updateProgress(progress: Float) { 213 | guard let _ = container else { return } 214 | 215 | currentProgress = progress 216 | 217 | let circleLayerInfo = getCircleLayerInfo(with: progress) 218 | let edgeLayerInfo = getEdgeLayerInfo(with: progress, circleLayerInfo: circleLayerInfo) 219 | let jointLayerInfo = getJointLayerInfo(with: progress, circleLayerInfo: circleLayerInfo, edgeLayerInfo: edgeLayerInfo) 220 | let imageLayerInfo = getImageLayerInfo(with: progress, circleLayerInfo: circleLayerInfo) 221 | let snapshotLayerInfo = getSnapshotLayerInfo(with: progress, circleLayerInfo: circleLayerInfo) 222 | 223 | circleLayer.path = circleLayerInfo.path 224 | edgeLayer.path = edgeLayerInfo.path 225 | jointLayer.path = jointLayerInfo.path 226 | 227 | snapshotLayer.position = snapshotLayerInfo.position 228 | snapshotLayer.opacity = snapshotLayerInfo.opacity 229 | 230 | imageLayer.position = imageLayerInfo.position 231 | imageLayer.opacity = imageLayerInfo.opacity 232 | imageLayer.transform = imageLayerInfo.transform 233 | } 234 | 235 | private func getCircleLayerInfo(with progress: Float) -> CircleLayerInfo { 236 | 237 | let radius: CGFloat 238 | 239 | if progress <= gapProgressValue { 240 | radius = circleShapeRadius 241 | } else { 242 | radius = circleShapeRadius * CGFloat(1 - (progress - gapProgressValue) / (1 - gapProgressValue)) 243 | } 244 | 245 | let locationY = effectCenterY 246 | let locationX = effectMaxWidth * CGFloat(progress) - radius 247 | 248 | let rect = CGRect(x: locationX - radius, y: locationY - radius, width: 2 * radius, height: 2 * radius) 249 | let bezierPath = UIBezierPath(ovalIn: rect) 250 | 251 | let centerPoint = CGPoint(x: locationX, y: locationY) 252 | let leftPoint = CGPoint(x: locationX - radius, y: locationY) 253 | let rightPoint = CGPoint(x: locationX + radius, y: locationY) 254 | 255 | return CircleLayerInfo(centerPoint: centerPoint, radius: radius, leftPoint: leftPoint, rightPoint: rightPoint, path: bezierPath.cgPath) 256 | } 257 | 258 | private func getEdgeLayerInfo(with progress: Float, circleLayerInfo: CircleLayerInfo) -> EdgeLayerInfo { 259 | 260 | let maxEdgeShapeWidth = effectMaxWidth * CGFloat(gapProgressValue) * edgeShapeWidthRate 261 | 262 | var width: CGFloat 263 | 264 | if progress <= gapProgressValue { 265 | width = min(circleLayerInfo.leftPoint.x - circleLayerInfo.radius / 2, maxEdgeShapeWidth * CGFloat(progress / gapProgressValue)) 266 | } else { 267 | width = maxEdgeShapeWidth * CGFloat(1 - (progress - gapProgressValue) / (1 - gapProgressValue)) 268 | } 269 | 270 | let locationX: CGFloat = 0 271 | let locationY = circleLayerInfo.centerPoint.y 272 | let height = effectHeight 273 | 274 | let minY: CGFloat = locationY - effectHeight / 2 275 | let maxY: CGFloat = minY + height 276 | 277 | let topPartHeight = locationY - minY 278 | let bottomPartHeight = maxY - locationY 279 | 280 | let verticalRate2: CGFloat = 0.44 281 | let verticaRate1: CGFloat = 0.71 282 | 283 | let horizontalRate1: CGFloat = 0.64 284 | let horizontalRateCenter: CGFloat = 1.36 285 | 286 | let top3Point = CGPoint(x: locationX, y: minY) 287 | let top2Point = CGPoint(x: locationX, y: minY + topPartHeight * verticalRate2) 288 | let top1Point = CGPoint(x: locationX + width * horizontalRate1, y: minY + topPartHeight * verticaRate1) 289 | let centerPoint = CGPoint(x: locationX + width * horizontalRateCenter, y: locationY) 290 | let bottom1Point = CGPoint(x: locationX + width * horizontalRate1, y: maxY - bottomPartHeight * verticaRate1) 291 | let bottom2Point = CGPoint(x: locationX, y: maxY - (bottomPartHeight * verticalRate2)) 292 | let bottom3Point = CGPoint(x: locationX, y: maxY) 293 | 294 | let bezierPath = UIBezierPath() 295 | bezierPath.move(to: top3Point) 296 | bezierPath.addCurve(to: top1Point, controlPoint1: top3Point, controlPoint2: top2Point) 297 | bezierPath.addCurve(to: bottom1Point, controlPoint1: centerPoint, controlPoint2: bottom1Point) 298 | bezierPath.addCurve(to: bottom3Point, controlPoint1: bottom1Point, controlPoint2: bottom2Point) 299 | bezierPath.close() 300 | 301 | let percentage = CGFloat(progress * jointShapeConstringencyRate) 302 | let topControlPoint = pointInLine(p1: top1Point, p2: centerPoint, percentage: percentage) 303 | let bottomControlPoint = pointInLine(p1: bottom1Point, p2: centerPoint, percentage: percentage) 304 | 305 | return EdgeLayerInfo(topPoint: top1Point, topControlPoint: topControlPoint, bottomPoint: bottom1Point, bottomControlPoint: bottomControlPoint, rightControlPoint: centerPoint, path: bezierPath.cgPath) 306 | } 307 | 308 | private func getJointLayerInfo(with progress: Float, circleLayerInfo: CircleLayerInfo, edgeLayerInfo: EdgeLayerInfo) -> JointLayerInfo { 309 | 310 | guard progress <= gapProgressValue else { 311 | 312 | let radius: CGFloat = circleLayerInfo.radius / 2.5 * CGFloat(1 - progress) 313 | let rect = CGRect(x: edgeLayerInfo.rightControlPoint.x - radius, y: edgeLayerInfo.rightControlPoint.y - radius, width: 2 * radius, height: 2 * radius) 314 | let bezierPath = UIBezierPath(ovalIn: rect) 315 | 316 | return JointLayerInfo(path: bezierPath.cgPath) 317 | } 318 | 319 | let circleTopControlPoint = CGPoint(x: circleLayerInfo.leftPoint.x - 10, y: edgeLayerInfo.topControlPoint.y) 320 | let circleTopPoint = calculateJointShapePoints(cp: circleTopControlPoint, circleShapeCenter: circleLayerInfo.centerPoint, circleShapeRadius: circleLayerInfo.radius).1 321 | 322 | let circleBottomControlPoint = CGPoint(x: circleLayerInfo.leftPoint.x - 10, y: edgeLayerInfo.bottomControlPoint.y) 323 | let circleBottomPoint = calculateJointShapePoints(cp: circleBottomControlPoint, circleShapeCenter: circleLayerInfo.centerPoint, circleShapeRadius: circleLayerInfo.radius).0 324 | 325 | let bezierPath = UIBezierPath() 326 | bezierPath.move(to: edgeLayerInfo.topPoint) 327 | bezierPath.addCurve(to: circleTopPoint, controlPoint1: edgeLayerInfo.topControlPoint, controlPoint2: circleTopPoint) 328 | bezierPath.addLine(to: circleBottomPoint) 329 | bezierPath.addCurve(to: edgeLayerInfo.bottomPoint, controlPoint1: circleBottomPoint, controlPoint2: edgeLayerInfo.bottomControlPoint) 330 | bezierPath.close() 331 | 332 | return JointLayerInfo(path: bezierPath.cgPath) 333 | } 334 | 335 | private func getSnapshotLayerInfo(with progress: Float, circleLayerInfo: CircleLayerInfo) -> SnapshotLayerInfo { 336 | let position = CGPoint(x: circleLayerInfo.rightPoint.x + snapshotLayer.bounds.width / 2, y: snapshotLayer.position.y) 337 | let opacity = 1 - progress / gapProgressValue 338 | return SnapshotLayerInfo(position: position, opacity: opacity) 339 | } 340 | 341 | private func getImageLayerInfo(with progress: Float, circleLayerInfo: CircleLayerInfo) -> ImageLayerInfo { 342 | 343 | let afterGapProgress = max(0, (progress - gapProgressValue) / (1 - gapProgressValue)) 344 | let position = circleLayerInfo.centerPoint 345 | let opacity = 1 - afterGapProgress 346 | let scale = CGFloat(1 - afterGapProgress * 1.2) 347 | let transform = CATransform3DMakeScale(scale, scale, 1) 348 | 349 | return ImageLayerInfo(position: position, opacity: opacity, transform: transform) 350 | } 351 | 352 | private func pointInLine(p1: CGPoint, p2: CGPoint, percentage: CGFloat) -> CGPoint { 353 | return CGPoint(x: p1.x + percentage * (p2.x - p1.x), y: p1.y + percentage * (p2.y - p1.y)) 354 | } 355 | 356 | private func calculateJointShapePoints(cp: CGPoint, circleShapeCenter: CGPoint, circleShapeRadius: CGFloat) -> (CGPoint, CGPoint) { 357 | let x = (circleShapeCenter.x + cp.x) / 2 358 | let y = (circleShapeCenter.y + cp.y) / 2 359 | let c1 = circleShapeCenter 360 | let c1r = circleShapeRadius 361 | let c2 = CGPoint(x: x, y: y) 362 | let (p1, p2) = findIntersections(centerCircle1: c1, radiusCircle1: c1r, centerCircle2: c2) 363 | 364 | return (p1, p2) 365 | } 366 | 367 | private func findIntersections(centerCircle1 c1: CGPoint, radiusCircle1 c1r: CGFloat, centerCircle2 c2: CGPoint) -> (CGPoint, CGPoint) { 368 | // The solution is to find tangents by calculation of intersection of two circles 369 | // https://www.mathsisfun.com/geometry/construct-circletangent.html 370 | // 371 | // Intersection of two circles 372 | // Discussion http://stackoverflow.com/questions/3349125/circle-circle-intersection-points 373 | // Description http://paulbourke.net/geometry/circlesphere/ 374 | 375 | //Calculate distance between centres of circle 376 | 377 | let c1c2 = CGPoint(x: c1.x - c2.x, y: c1.y - c2.y) 378 | let d = sqrt(c1c2.x * c1c2.x + c1c2.y * c1c2.y) 379 | 380 | let c2r = d //in our case 381 | let m = c1r + c2r 382 | var n = c1r - c2r 383 | 384 | if (n < 0) { 385 | n = n * -1 386 | } 387 | 388 | //No solns 389 | if (d > m) { 390 | return (CGPoint.zero, CGPoint.zero) 391 | } 392 | //Circle are contained within each other 393 | if (d < n) { 394 | return (CGPoint.zero, CGPoint.zero) 395 | } 396 | //Circles are the same 397 | if (d == 0 && c1r == c2r) { 398 | return (CGPoint.zero, CGPoint.zero) 399 | } 400 | 401 | let a = (c1r * c1r - c2r * c2r + d * d) / (2 * d) 402 | 403 | let h = sqrt(c1r * c1r - a * a) 404 | 405 | //Calculate point p, where the line through the circle intersection points crosses the line between the circle centers. 406 | 407 | var x = c1.x + (a / d) * (c2.x - c1.x) 408 | var y = c1.y + (a / d) * (c2.y - c1.y) 409 | let p = CGPoint(x: x, y: y) 410 | 411 | //1 Intersection , circles are touching 412 | if (d == c1r + c2r) { 413 | return (p, CGPoint.zero) 414 | } 415 | 416 | //2 Intersections 417 | //Intersection 1 418 | x = p.x + (h / d) * (c2.y - c1.y) 419 | y = p.y - (h / d) * (c2.x - c1.x) 420 | let p1 = CGPoint(x: x, y: y) 421 | 422 | //Intersection 2 423 | x = p.x - (h / d) * (c2.y - c1.y) 424 | y = p.y + (h / d) * (c2.x - c1.x) 425 | let p2 = CGPoint(x: x, y: y) 426 | 427 | return (p1, p2) 428 | } 429 | } 430 | 431 | extension UIImage { 432 | convenience init(view: UIView) { 433 | UIGraphicsBeginImageContextWithOptions(view.frame.size, false, 0.0) 434 | view.layer.render(in: UIGraphicsGetCurrentContext()!) 435 | let image = UIGraphicsGetImageFromCurrentImageContext() 436 | UIGraphicsEndImageContext() 437 | self.init(cgImage: image!.cgImage!, scale: UIScreen.main.scale, orientation: .up) 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /gooey-cell/Classes/GooeyEffectTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GooeyEffectTableViewCell.swift 3 | // gooey-cell 4 | // 5 | // Created by Прегер Глеб on 22/01/2019. 6 | // Copyright © 2019 Cuberto. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol GooeyCellDelegate: class { 12 | func gooeyCellActionConfig(for cell: UITableViewCell, direction: GooeyEffect.Direction) -> GooeyEffectTableViewCell.ActionConfig? 13 | func gooeyCellActionTriggered(for cell: UITableViewCell, direction: GooeyEffect.Direction) 14 | } 15 | 16 | open class GooeyEffectTableViewCell: UITableViewCell { 17 | 18 | public struct ActionConfig { 19 | let effectConfig: GooeyEffect.Config 20 | let isCellDeletingAction: Bool 21 | 22 | public init(effectConfig: GooeyEffect.Config, isCellDeletingAction: Bool) { 23 | self.effectConfig = effectConfig 24 | self.isCellDeletingAction = isCellDeletingAction 25 | } 26 | } 27 | 28 | private var effect: GooeyEffect? 29 | private var actionConfig: ActionConfig? 30 | private var gesture: UIPanGestureRecognizer! 31 | 32 | open weak var gooeyCellDelegate: GooeyCellDelegate? 33 | 34 | public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 35 | super.init(style: style, reuseIdentifier: reuseIdentifier) 36 | addGesture() 37 | } 38 | 39 | required public init?(coder aDecoder: NSCoder) { 40 | super.init(coder: aDecoder) 41 | addGesture() 42 | } 43 | 44 | override open func prepareForReuse() { 45 | super.prepareForReuse() 46 | effect = nil 47 | actionConfig = nil 48 | gesture.isEnabled = true 49 | } 50 | 51 | private func addGesture() { 52 | gesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized)) 53 | gesture.delegate = self 54 | self.addGestureRecognizer(gesture) 55 | } 56 | 57 | @objc private func panGestureRecognized(_ gesture: UIPanGestureRecognizer) { 58 | 59 | switch gesture.state { 60 | case .began: 61 | 62 | let direction: GooeyEffect.Direction = gesture.velocity(in: self).x > 0 ? .toRight : .toLeft 63 | 64 | guard self.effect == nil, 65 | let actionConfig = gooeyCellDelegate?.gooeyCellActionConfig(for: self, direction: direction) else { 66 | 67 | gesture.isEnabled = false 68 | gesture.isEnabled = true 69 | return 70 | } 71 | 72 | self.actionConfig = actionConfig 73 | 74 | let verticalPosition = Float(gesture.location(in: self).y / self.bounds.height) 75 | 76 | effect = GooeyEffect(to: self, 77 | verticalPosition: verticalPosition, 78 | direction: direction, 79 | config: actionConfig.effectConfig) 80 | 81 | case .changed: 82 | 83 | guard let effect = effect else { return } 84 | 85 | var progress = Float(gesture.translation(in: self).x / effect.effectMaxWidth) 86 | 87 | if isProgressInCorrectDirection(progress) { 88 | progress = abs(progress) 89 | } else { 90 | progress = 0 91 | } 92 | 93 | let nonlinearProgressLength: Float = 0.15 94 | let nonlinearProgressStart: Float = effect.gapProgressValue - nonlinearProgressLength 95 | 96 | let effectProgress: Float 97 | 98 | if progress > nonlinearProgressStart { 99 | 100 | let localProgress = (progress - (nonlinearProgressStart)) / nonlinearProgressLength 101 | let rate = Float(log10(Double(1 + localProgress))) 102 | 103 | if rate > 1 { 104 | effectProgress = effect.gapProgressValue 105 | } else { 106 | effectProgress = nonlinearProgressStart + nonlinearProgressLength * rate 107 | } 108 | 109 | } else { 110 | effectProgress = progress 111 | } 112 | 113 | effect.updateProgress(progress: effectProgress) 114 | 115 | case .cancelled, .ended, .failed: 116 | 117 | guard let effect = effect else { return } 118 | 119 | gesture.isEnabled = false 120 | 121 | let progress = Float(gesture.translation(in: self).x / effect.effectMaxWidth) 122 | 123 | let finalEffectProgress: Float 124 | 125 | if isProgressInCorrectDirection(progress), gesture.state == .ended { 126 | finalEffectProgress = abs(progress) < effect.gapProgressValue ? 0 : 1 127 | } else { 128 | finalEffectProgress = 0 129 | } 130 | 131 | effect.animateToProgress(finalEffectProgress) { [weak self] in 132 | guard let self = self else { return } 133 | 134 | if finalEffectProgress == 1 { 135 | 136 | self.gooeyCellDelegate?.gooeyCellActionTriggered(for: self, direction: effect.direction) 137 | 138 | let saveFinalEffectState = self.actionConfig?.isCellDeletingAction == true 139 | 140 | if !saveFinalEffectState { 141 | self.effect?.removeEffect(animated: true) { [weak self] in 142 | self?.effect = nil 143 | } 144 | } 145 | } else { 146 | self.effect = nil 147 | } 148 | 149 | gesture.isEnabled = true 150 | } 151 | 152 | case .possible: 153 | break 154 | } 155 | } 156 | 157 | private func isProgressInCorrectDirection(_ progress: Float) -> Bool { 158 | guard let effect = effect else { return false } 159 | 160 | if progress < 0 && effect.direction == .toRight || 161 | progress > 0 && effect.direction == .toLeft { 162 | 163 | return false 164 | } else { 165 | return true 166 | } 167 | } 168 | 169 | override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 170 | if gestureRecognizer == gesture, 171 | abs(gesture.translation(in: self).y) > 0 { 172 | return false 173 | } 174 | return true 175 | } 176 | } 177 | --------------------------------------------------------------------------------