├── .DS_Store ├── LICENSE ├── PUCoverFlow.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcuserdata │ │ └── abhi.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── abhi.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── PUCoverFlow ├── .DS_Store ├── AppDelegate.swift ├── Assets.xcassets │ ├── .DS_Store │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── blogComment.imageset │ │ ├── Contents.json │ │ └── blogComment@3x.png │ ├── blogLike.imageset │ │ ├── Contents.json │ │ └── blogLike@3x.png │ └── icMask1.imageset │ │ ├── Contents.json │ │ └── icMask1.png ├── CarouselCollectionViewCell.swift ├── Character.swift ├── Info.plist ├── PUCoverFlowLayout │ └── PUCoverFlowLayout.swift ├── ViewController.swift └── Views │ ├── .DS_Store │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ └── CarouselCollectionViewCell.xib └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Payal Umraliya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 38FA67FE295D7B760076E8B1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FA67FD295D7B760076E8B1 /* AppDelegate.swift */; }; 11 | 38FA6815295D7DF80076E8B1 /* SDWebImage in Frameworks */ = {isa = PBXBuildFile; productRef = 38FA6814295D7DF80076E8B1 /* SDWebImage */; }; 12 | 38FA681F295D7E3E0076E8B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38FA6816295D7E3E0076E8B1 /* Assets.xcassets */; }; 13 | 38FA6820295D7E3E0076E8B1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 38FA6818295D7E3E0076E8B1 /* LaunchScreen.storyboard */; }; 14 | 38FA6821295D7E3E0076E8B1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 38FA681A295D7E3E0076E8B1 /* Main.storyboard */; }; 15 | 38FA6826295D7EC50076E8B1 /* PUCoverFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FA6825295D7EC50076E8B1 /* PUCoverFlowLayout.swift */; }; 16 | 38FA6827295D83600076E8B1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FA681C295D7E3E0076E8B1 /* ViewController.swift */; }; 17 | 38FA682C295D8CA80076E8B1 /* CarouselCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FA682B295D8CA80076E8B1 /* CarouselCollectionViewCell.swift */; }; 18 | 38FA682E295D8F840076E8B1 /* CarouselCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 38FA682D295D8F840076E8B1 /* CarouselCollectionViewCell.xib */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 38FA67FA295D7B760076E8B1 /* PUCoverFlow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PUCoverFlow.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 38FA67FD295D7B760076E8B1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | 38FA680B295D7B770076E8B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | 38FA6816295D7E3E0076E8B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | 38FA6819295D7E3E0076E8B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 27 | 38FA681B295D7E3E0076E8B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 28 | 38FA681C295D7E3E0076E8B1 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 29 | 38FA6825295D7EC50076E8B1 /* PUCoverFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PUCoverFlowLayout.swift; sourceTree = ""; }; 30 | 38FA682B295D8CA80076E8B1 /* CarouselCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarouselCollectionViewCell.swift; sourceTree = ""; }; 31 | 38FA682D295D8F840076E8B1 /* CarouselCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CarouselCollectionViewCell.xib; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 38FA67F7295D7B760076E8B1 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | 38FA6815295D7DF80076E8B1 /* SDWebImage in Frameworks */, 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 38FA67F1295D7B760076E8B1 = { 47 | isa = PBXGroup; 48 | children = ( 49 | 38FA67FC295D7B760076E8B1 /* PUCoverFlow */, 50 | 38FA67FB295D7B760076E8B1 /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | 38FA67FB295D7B760076E8B1 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 38FA67FA295D7B760076E8B1 /* PUCoverFlow.app */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | 38FA67FC295D7B760076E8B1 /* PUCoverFlow */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 38FA67FD295D7B760076E8B1 /* AppDelegate.swift */, 66 | 38FA6829295D8A8C0076E8B1 /* Views */, 67 | 38FA682A295D8AB30076E8B1 /* PUCoverFlowLayout */, 68 | 38FA681C295D7E3E0076E8B1 /* ViewController.swift */, 69 | 38FA682B295D8CA80076E8B1 /* CarouselCollectionViewCell.swift */, 70 | 38FA680B295D7B770076E8B1 /* Info.plist */, 71 | 38FA6816295D7E3E0076E8B1 /* Assets.xcassets */, 72 | ); 73 | path = PUCoverFlow; 74 | sourceTree = ""; 75 | }; 76 | 38FA6817295D7E3E0076E8B1 /* Base.lproj */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 38FA6818295D7E3E0076E8B1 /* LaunchScreen.storyboard */, 80 | 38FA681A295D7E3E0076E8B1 /* Main.storyboard */, 81 | ); 82 | path = Base.lproj; 83 | sourceTree = ""; 84 | }; 85 | 38FA6829295D8A8C0076E8B1 /* Views */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 38FA6817295D7E3E0076E8B1 /* Base.lproj */, 89 | 38FA682D295D8F840076E8B1 /* CarouselCollectionViewCell.xib */, 90 | ); 91 | path = Views; 92 | sourceTree = ""; 93 | }; 94 | 38FA682A295D8AB30076E8B1 /* PUCoverFlowLayout */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 38FA6825295D7EC50076E8B1 /* PUCoverFlowLayout.swift */, 98 | ); 99 | path = PUCoverFlowLayout; 100 | sourceTree = ""; 101 | }; 102 | /* End PBXGroup section */ 103 | 104 | /* Begin PBXNativeTarget section */ 105 | 38FA67F9295D7B760076E8B1 /* PUCoverFlow */ = { 106 | isa = PBXNativeTarget; 107 | buildConfigurationList = 38FA680E295D7B770076E8B1 /* Build configuration list for PBXNativeTarget "PUCoverFlow" */; 108 | buildPhases = ( 109 | 38FA67F6295D7B760076E8B1 /* Sources */, 110 | 38FA67F7295D7B760076E8B1 /* Frameworks */, 111 | 38FA67F8295D7B760076E8B1 /* Resources */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = PUCoverFlow; 118 | packageProductDependencies = ( 119 | 38FA6814295D7DF80076E8B1 /* SDWebImage */, 120 | ); 121 | productName = PUCoverFlow; 122 | productReference = 38FA67FA295D7B760076E8B1 /* PUCoverFlow.app */; 123 | productType = "com.apple.product-type.application"; 124 | }; 125 | /* End PBXNativeTarget section */ 126 | 127 | /* Begin PBXProject section */ 128 | 38FA67F2295D7B760076E8B1 /* Project object */ = { 129 | isa = PBXProject; 130 | attributes = { 131 | BuildIndependentTargetsInParallel = 1; 132 | LastSwiftUpdateCheck = 1410; 133 | LastUpgradeCheck = 1410; 134 | TargetAttributes = { 135 | 38FA67F9295D7B760076E8B1 = { 136 | CreatedOnToolsVersion = 14.1; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = 38FA67F5295D7B760076E8B1 /* Build configuration list for PBXProject "PUCoverFlow" */; 141 | compatibilityVersion = "Xcode 14.0"; 142 | developmentRegion = en; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | Base, 147 | ); 148 | mainGroup = 38FA67F1295D7B760076E8B1; 149 | packageReferences = ( 150 | 38FA6813295D7DF80076E8B1 /* XCRemoteSwiftPackageReference "SDWebImage" */, 151 | ); 152 | productRefGroup = 38FA67FB295D7B760076E8B1 /* Products */; 153 | projectDirPath = ""; 154 | projectRoot = ""; 155 | targets = ( 156 | 38FA67F9295D7B760076E8B1 /* PUCoverFlow */, 157 | ); 158 | }; 159 | /* End PBXProject section */ 160 | 161 | /* Begin PBXResourcesBuildPhase section */ 162 | 38FA67F8295D7B760076E8B1 /* Resources */ = { 163 | isa = PBXResourcesBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | 38FA682E295D8F840076E8B1 /* CarouselCollectionViewCell.xib in Resources */, 167 | 38FA6821295D7E3E0076E8B1 /* Main.storyboard in Resources */, 168 | 38FA681F295D7E3E0076E8B1 /* Assets.xcassets in Resources */, 169 | 38FA6820295D7E3E0076E8B1 /* LaunchScreen.storyboard in Resources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXResourcesBuildPhase section */ 174 | 175 | /* Begin PBXSourcesBuildPhase section */ 176 | 38FA67F6295D7B760076E8B1 /* Sources */ = { 177 | isa = PBXSourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 38FA682C295D8CA80076E8B1 /* CarouselCollectionViewCell.swift in Sources */, 181 | 38FA6827295D83600076E8B1 /* ViewController.swift in Sources */, 182 | 38FA6826295D7EC50076E8B1 /* PUCoverFlowLayout.swift in Sources */, 183 | 38FA67FE295D7B760076E8B1 /* AppDelegate.swift in Sources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXSourcesBuildPhase section */ 188 | 189 | /* Begin PBXVariantGroup section */ 190 | 38FA6818295D7E3E0076E8B1 /* LaunchScreen.storyboard */ = { 191 | isa = PBXVariantGroup; 192 | children = ( 193 | 38FA6819295D7E3E0076E8B1 /* Base */, 194 | ); 195 | name = LaunchScreen.storyboard; 196 | sourceTree = ""; 197 | }; 198 | 38FA681A295D7E3E0076E8B1 /* Main.storyboard */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | 38FA681B295D7E3E0076E8B1 /* Base */, 202 | ); 203 | name = Main.storyboard; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXVariantGroup section */ 207 | 208 | /* Begin XCBuildConfiguration section */ 209 | 38FA680C295D7B770076E8B1 /* Debug */ = { 210 | isa = XCBuildConfiguration; 211 | buildSettings = { 212 | ALWAYS_SEARCH_USER_PATHS = NO; 213 | CLANG_ANALYZER_NONNULL = YES; 214 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 216 | CLANG_ENABLE_MODULES = YES; 217 | CLANG_ENABLE_OBJC_ARC = YES; 218 | CLANG_ENABLE_OBJC_WEAK = YES; 219 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 220 | CLANG_WARN_BOOL_CONVERSION = YES; 221 | CLANG_WARN_COMMA = YES; 222 | CLANG_WARN_CONSTANT_CONVERSION = YES; 223 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 224 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 225 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 226 | CLANG_WARN_EMPTY_BODY = YES; 227 | CLANG_WARN_ENUM_CONVERSION = YES; 228 | CLANG_WARN_INFINITE_RECURSION = YES; 229 | CLANG_WARN_INT_CONVERSION = YES; 230 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 231 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 232 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 233 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 234 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 235 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 236 | CLANG_WARN_STRICT_PROTOTYPES = YES; 237 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 238 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 239 | CLANG_WARN_UNREACHABLE_CODE = YES; 240 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 241 | COPY_PHASE_STRIP = NO; 242 | DEBUG_INFORMATION_FORMAT = dwarf; 243 | ENABLE_STRICT_OBJC_MSGSEND = YES; 244 | ENABLE_TESTABILITY = YES; 245 | GCC_C_LANGUAGE_STANDARD = gnu11; 246 | GCC_DYNAMIC_NO_PIC = NO; 247 | GCC_NO_COMMON_BLOCKS = YES; 248 | GCC_OPTIMIZATION_LEVEL = 0; 249 | GCC_PREPROCESSOR_DEFINITIONS = ( 250 | "DEBUG=1", 251 | "$(inherited)", 252 | ); 253 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 254 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 255 | GCC_WARN_UNDECLARED_SELECTOR = YES; 256 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 257 | GCC_WARN_UNUSED_FUNCTION = YES; 258 | GCC_WARN_UNUSED_VARIABLE = YES; 259 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 260 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 261 | MTL_FAST_MATH = YES; 262 | ONLY_ACTIVE_ARCH = YES; 263 | SDKROOT = iphoneos; 264 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 266 | }; 267 | name = Debug; 268 | }; 269 | 38FA680D295D7B770076E8B1 /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ALWAYS_SEARCH_USER_PATHS = NO; 273 | CLANG_ANALYZER_NONNULL = YES; 274 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 276 | CLANG_ENABLE_MODULES = YES; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | CLANG_ENABLE_OBJC_WEAK = YES; 279 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 280 | CLANG_WARN_BOOL_CONVERSION = YES; 281 | CLANG_WARN_COMMA = YES; 282 | CLANG_WARN_CONSTANT_CONVERSION = YES; 283 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INFINITE_RECURSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 291 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 292 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 293 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 294 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 296 | CLANG_WARN_STRICT_PROTOTYPES = YES; 297 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 298 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 299 | CLANG_WARN_UNREACHABLE_CODE = YES; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | COPY_PHASE_STRIP = NO; 302 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 303 | ENABLE_NS_ASSERTIONS = NO; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | GCC_C_LANGUAGE_STANDARD = gnu11; 306 | GCC_NO_COMMON_BLOCKS = YES; 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | IPHONEOS_DEPLOYMENT_TARGET = 16.1; 314 | MTL_ENABLE_DEBUG_INFO = NO; 315 | MTL_FAST_MATH = YES; 316 | SDKROOT = iphoneos; 317 | SWIFT_COMPILATION_MODE = wholemodule; 318 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 319 | VALIDATE_PRODUCT = YES; 320 | }; 321 | name = Release; 322 | }; 323 | 38FA680F295D7B770076E8B1 /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 327 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 328 | CODE_SIGN_IDENTITY = "Apple Development"; 329 | CODE_SIGN_STYLE = Automatic; 330 | CURRENT_PROJECT_VERSION = 1; 331 | DEVELOPMENT_TEAM = 62794643WB; 332 | GENERATE_INFOPLIST_FILE = YES; 333 | INFOPLIST_FILE = PUCoverFlow/Info.plist; 334 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 335 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 336 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 337 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 338 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 339 | LD_RUNPATH_SEARCH_PATHS = ( 340 | "$(inherited)", 341 | "@executable_path/Frameworks", 342 | ); 343 | MARKETING_VERSION = 1.0; 344 | PRODUCT_BUNDLE_IDENTIFIER = com.checkmate.PUCoverFlow; 345 | PRODUCT_NAME = "$(TARGET_NAME)"; 346 | PROVISIONING_PROFILE_SPECIFIER = ""; 347 | SWIFT_EMIT_LOC_STRINGS = YES; 348 | SWIFT_VERSION = 5.0; 349 | TARGETED_DEVICE_FAMILY = "1,2"; 350 | }; 351 | name = Debug; 352 | }; 353 | 38FA6810295D7B770076E8B1 /* Release */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 357 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 358 | CODE_SIGN_IDENTITY = "Apple Development"; 359 | CODE_SIGN_STYLE = Automatic; 360 | CURRENT_PROJECT_VERSION = 1; 361 | DEVELOPMENT_TEAM = 62794643WB; 362 | GENERATE_INFOPLIST_FILE = YES; 363 | INFOPLIST_FILE = PUCoverFlow/Info.plist; 364 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 365 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 366 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 367 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 368 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 369 | LD_RUNPATH_SEARCH_PATHS = ( 370 | "$(inherited)", 371 | "@executable_path/Frameworks", 372 | ); 373 | MARKETING_VERSION = 1.0; 374 | PRODUCT_BUNDLE_IDENTIFIER = com.checkmate.PUCoverFlow; 375 | PRODUCT_NAME = "$(TARGET_NAME)"; 376 | PROVISIONING_PROFILE_SPECIFIER = ""; 377 | SWIFT_EMIT_LOC_STRINGS = YES; 378 | SWIFT_VERSION = 5.0; 379 | TARGETED_DEVICE_FAMILY = "1,2"; 380 | }; 381 | name = Release; 382 | }; 383 | /* End XCBuildConfiguration section */ 384 | 385 | /* Begin XCConfigurationList section */ 386 | 38FA67F5295D7B760076E8B1 /* Build configuration list for PBXProject "PUCoverFlow" */ = { 387 | isa = XCConfigurationList; 388 | buildConfigurations = ( 389 | 38FA680C295D7B770076E8B1 /* Debug */, 390 | 38FA680D295D7B770076E8B1 /* Release */, 391 | ); 392 | defaultConfigurationIsVisible = 0; 393 | defaultConfigurationName = Release; 394 | }; 395 | 38FA680E295D7B770076E8B1 /* Build configuration list for PBXNativeTarget "PUCoverFlow" */ = { 396 | isa = XCConfigurationList; 397 | buildConfigurations = ( 398 | 38FA680F295D7B770076E8B1 /* Debug */, 399 | 38FA6810295D7B770076E8B1 /* Release */, 400 | ); 401 | defaultConfigurationIsVisible = 0; 402 | defaultConfigurationName = Release; 403 | }; 404 | /* End XCConfigurationList section */ 405 | 406 | /* Begin XCRemoteSwiftPackageReference section */ 407 | 38FA6813295D7DF80076E8B1 /* XCRemoteSwiftPackageReference "SDWebImage" */ = { 408 | isa = XCRemoteSwiftPackageReference; 409 | repositoryURL = "https://github.com/SDWebImage/SDWebImage.git"; 410 | requirement = { 411 | kind = upToNextMajorVersion; 412 | minimumVersion = 5.0.0; 413 | }; 414 | }; 415 | /* End XCRemoteSwiftPackageReference section */ 416 | 417 | /* Begin XCSwiftPackageProductDependency section */ 418 | 38FA6814295D7DF80076E8B1 /* SDWebImage */ = { 419 | isa = XCSwiftPackageProductDependency; 420 | package = 38FA6813295D7DF80076E8B1 /* XCRemoteSwiftPackageReference "SDWebImage" */; 421 | productName = SDWebImage; 422 | }; 423 | /* End XCSwiftPackageProductDependency section */ 424 | }; 425 | rootObject = 38FA67F2295D7B760076E8B1 /* Project object */; 426 | } 427 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "sdwebimage", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/SDWebImage/SDWebImage.git", 7 | "state" : { 8 | "revision" : "4178d12a44691182c2eb79c70281b14cb73f4cbf", 9 | "version" : "5.14.3" 10 | } 11 | } 12 | ], 13 | "version" : 2 14 | } 15 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/project.xcworkspace/xcuserdata/abhi.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow.xcodeproj/project.xcworkspace/xcuserdata/abhi.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/xcuserdata/abhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /PUCoverFlow.xcodeproj/xcuserdata/abhi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PUCoverFlow.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /PUCoverFlow/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/.DS_Store -------------------------------------------------------------------------------- /PUCoverFlow/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PUCoverFlow 4 | // 5 | // Created by Payal Umraliya on 29/12/22. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | var window: UIWindow? 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/blogComment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "blogComment@3x.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/blogComment.imageset/blogComment@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/Assets.xcassets/blogComment.imageset/blogComment@3x.png -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/blogLike.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "blogLike@3x.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/blogLike.imageset/blogLike@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/Assets.xcassets/blogLike.imageset/blogLike@3x.png -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/icMask1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icMask1.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PUCoverFlow/Assets.xcassets/icMask1.imageset/icMask1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/Assets.xcassets/icMask1.imageset/icMask1.png -------------------------------------------------------------------------------- /PUCoverFlow/CarouselCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CarouselCollectionViewCell.swift 3 | // Created by Payal Umraliya on 29/12/22. 4 | // 5 | 6 | import UIKit 7 | 8 | class CarouselCollectionViewCell: UICollectionViewCell { 9 | @IBOutlet weak var heightStacklabels: NSLayoutConstraint! 10 | @IBOutlet weak var vwmain: UIView! 11 | @IBOutlet weak var lbltag: UILabel! 12 | @IBOutlet weak var lbltitle: UILabel! 13 | @IBOutlet weak var lbldescr: UILabel! 14 | @IBOutlet weak var imgshadow: UIImageView! 15 | @IBOutlet weak var image: UIImageView! 16 | @IBOutlet weak var stacklabels: UIStackView! 17 | static let identifier = "CarouselCollectionViewCell" 18 | 19 | required init?(coder aDecoder: NSCoder) { 20 | super.init(coder: aDecoder) 21 | // self.contentView.layer.masksToBounds = true 22 | // self.layer.cornerRadius = 10 //max(self.frame.size.width, self.frame.size.height) / 2 23 | // self.layer.borderWidth = 10 24 | self.layer.borderColor = UIColor(red: 110.0/255.0, green: 80.0/255.0, blue: 140.0/255.0, alpha: 1.0).cgColor 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PUCoverFlow/Character.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Character.swift 3 | // UPCarouselFlowLayoutDemo 4 | // 5 | // Created by Paul Ulric on 28/06/2016. 6 | // Copyright © 2016 Paul Ulric. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Character { 12 | let imageName: String! 13 | let name: String! 14 | let movie: String! 15 | let title :String! 16 | let subtitle:String! 17 | let tag:String! 18 | } 19 | -------------------------------------------------------------------------------- /PUCoverFlow/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /PUCoverFlow/PUCoverFlowLayout/PUCoverFlowLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PUCoverFlowLayout.swift 3 | // PUCoverFlow 4 | // 5 | // Created by Payal Umraliya on 29/12/22. 6 | // 7 | 8 | import UIKit 9 | 10 | public enum PUCoverFlowLayoutSpacingMode { 11 | case fixed(spacing: CGFloat) 12 | case overlap(visibleOffset: CGFloat) 13 | } 14 | 15 | open class PUCoverFlowLayout: UICollectionViewFlowLayout { 16 | 17 | fileprivate struct LayoutState { 18 | var size: CGSize 19 | var direction: UICollectionView.ScrollDirection 20 | func isEqual(_ otherState: LayoutState) -> Bool { 21 | return self.size.equalTo(otherState.size) && self.direction == otherState.direction 22 | } 23 | } 24 | 25 | @IBInspectable open var sideItemScale: CGFloat = 0.6 26 | @IBInspectable open var sideItemAlpha: CGFloat = 0.6 27 | @IBInspectable open var sideItemShift: CGFloat = 0.0 28 | open var spacingMode = PUCoverFlowLayoutSpacingMode.fixed(spacing: 40) 29 | 30 | fileprivate var state = LayoutState(size: CGSize.zero, direction: .horizontal) 31 | 32 | 33 | override open func prepare() { 34 | super.prepare() 35 | let currentState = LayoutState(size: self.collectionView!.bounds.size, direction: self.scrollDirection) 36 | 37 | if !self.state.isEqual(currentState) { 38 | self.setupCollectionView() 39 | self.updateLayout() 40 | self.state = currentState 41 | } 42 | } 43 | 44 | fileprivate func setupCollectionView() { 45 | guard let collectionView = self.collectionView else { return } 46 | if collectionView.decelerationRate != UIScrollView.DecelerationRate.fast { 47 | collectionView.decelerationRate = UIScrollView.DecelerationRate.fast 48 | } 49 | } 50 | 51 | fileprivate func updateLayout() { 52 | guard let collectionView = self.collectionView else { return } 53 | 54 | let collectionSize = collectionView.bounds.size 55 | let isHorizontal = (self.scrollDirection == .horizontal) 56 | 57 | let yInset = (collectionSize.height - self.itemSize.height) / 2 58 | let xInset = (collectionSize.width - self.itemSize.width) / 2 59 | self.sectionInset = UIEdgeInsets.init(top: yInset, left: xInset, bottom: yInset, right: xInset) 60 | 61 | let side = isHorizontal ? self.itemSize.width : self.itemSize.height 62 | let scaledItemOffset = (side - side*self.sideItemScale) / 2 63 | switch self.spacingMode { 64 | case .fixed(let spacing): 65 | self.minimumLineSpacing = spacing - scaledItemOffset 66 | case .overlap(let visibleOffset): 67 | let fullSizeSideItemOverlap = visibleOffset + scaledItemOffset 68 | let inset = isHorizontal ? xInset : yInset 69 | self.minimumLineSpacing = inset - fullSizeSideItemOverlap 70 | } 71 | } 72 | 73 | override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { 74 | return true 75 | } 76 | 77 | override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 78 | guard let superAttributes = super.layoutAttributesForElements(in: rect), 79 | let attributes = NSArray(array: superAttributes, copyItems: true) as? [UICollectionViewLayoutAttributes] 80 | else { return nil } 81 | return attributes.map({ self.transformLayoutAttributes($0) }) 82 | } 83 | 84 | fileprivate func transformLayoutAttributes(_ attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { 85 | guard let collectionView = self.collectionView else { return attributes } 86 | let isHorizontal = (self.scrollDirection == .horizontal) 87 | 88 | let collectionCenter = isHorizontal ? collectionView.frame.size.width/2 : collectionView.frame.size.height/2 89 | let offset = isHorizontal ? collectionView.contentOffset.x : collectionView.contentOffset.y 90 | let normalizedCenter = (isHorizontal ? attributes.center.x : attributes.center.y) - offset 91 | 92 | let maxDistance = (isHorizontal ? self.itemSize.width : self.itemSize.height) + self.minimumLineSpacing 93 | let distance = min(abs(collectionCenter - normalizedCenter), maxDistance) 94 | let ratio = (maxDistance - distance)/maxDistance 95 | 96 | let alpha = ratio * (1 - self.sideItemAlpha) + self.sideItemAlpha 97 | let scale = ratio * (1 - self.sideItemScale) + self.sideItemScale 98 | let shift = (1 - ratio) * self.sideItemShift 99 | attributes.alpha = alpha 100 | attributes.transform3D = CATransform3DScale(CATransform3DIdentity, scale, scale, 1) 101 | attributes.zIndex = Int(alpha * 10) 102 | 103 | if isHorizontal { 104 | attributes.center.y = attributes.center.y + shift 105 | } else { 106 | attributes.center.x = attributes.center.x + shift 107 | } 108 | 109 | return attributes 110 | } 111 | 112 | override open func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { 113 | guard let collectionView = collectionView , !collectionView.isPagingEnabled, 114 | let layoutAttributes = self.layoutAttributesForElements(in: collectionView.bounds) 115 | else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset) } 116 | 117 | let isHorizontal = (self.scrollDirection == .horizontal) 118 | 119 | let midSide = (isHorizontal ? collectionView.bounds.size.width : collectionView.bounds.size.height) / 2 120 | let proposedContentOffsetCenterOrigin = (isHorizontal ? proposedContentOffset.x : proposedContentOffset.y) + midSide 121 | 122 | var targetContentOffset: CGPoint 123 | if isHorizontal { 124 | let closest = layoutAttributes.sorted { abs($0.center.x - proposedContentOffsetCenterOrigin) < abs($1.center.x - proposedContentOffsetCenterOrigin) }.first ?? UICollectionViewLayoutAttributes() 125 | targetContentOffset = CGPoint(x: floor(closest.center.x - midSide), y: proposedContentOffset.y) 126 | } 127 | else { 128 | let closest = layoutAttributes.sorted { abs($0.center.y - proposedContentOffsetCenterOrigin) < abs($1.center.y - proposedContentOffsetCenterOrigin) }.first ?? UICollectionViewLayoutAttributes() 129 | targetContentOffset = CGPoint(x: proposedContentOffset.x, y: floor(closest.center.y - midSide)) 130 | } 131 | 132 | return targetContentOffset 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /PUCoverFlow/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PUCoverFlow 4 | // 5 | // Created by Payal Umraliya on 29/12/22. 6 | // 7 | import UIKit 8 | import SDWebImage 9 | class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { 10 | @IBOutlet weak var vwactions: UIView! 11 | 12 | @IBOutlet weak var btncomment: UIButton! 13 | @IBOutlet weak var btnlike: UIButton! 14 | @IBOutlet weak var collectionView: UICollectionView! 15 | fileprivate var items = [Character]() 16 | var timer = Timer() 17 | fileprivate var currentPage: Int = 0 { 18 | didSet { 19 | self.vwactions.alpha = 0 20 | UIView.animate(withDuration: 0.3) { 21 | self.vwactions.alpha = 1 22 | 23 | } 24 | } 25 | } 26 | 27 | fileprivate var pageSize: CGSize { 28 | let layout = self.collectionView.collectionViewLayout as! PUCoverFlowLayout 29 | var pageSize = layout.itemSize 30 | if layout.scrollDirection == .horizontal { 31 | pageSize.width += layout.minimumLineSpacing 32 | } else { 33 | pageSize.height += layout.minimumLineSpacing 34 | } 35 | print("Page : \(pageSize)") 36 | return pageSize 37 | } 38 | 39 | fileprivate var orientation: UIDeviceOrientation { 40 | return UIDevice.current.orientation 41 | } 42 | override func viewDidLoad() 43 | { 44 | super.viewDidLoad() 45 | // self.collectionView.isPagingEnabled = true 46 | self.collectionView.register(UINib(nibName: "CarouselCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CarouselCollectionViewCell") 47 | self.setupLayout() 48 | loadDataAtCenter(true) 49 | DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { 50 | self.loadDataAtCenter() 51 | } 52 | NotificationCenter.default.addObserver(self, selector: #selector(ViewController.rotationDidChange), name: UIDevice.orientationDidChangeNotification, object: nil) 53 | } 54 | 55 | func loadDataAtCenter( _ isShimmer:Bool = false) 56 | { 57 | self.currentPage = 0 58 | if isShimmer 59 | { 60 | 61 | self.items = self.createShimmerItems() 62 | self.timer.invalidate() 63 | self.vwactions.isHidden = true 64 | self.collectionView.reloadData() 65 | self.collectionView.startShimmeringEffect() 66 | } 67 | else 68 | { 69 | self.items = self.createItems() 70 | self.vwactions.isHidden = false 71 | self.collectionView.reloadData() 72 | self.collectionView.stopShimmeringEffect() 73 | self.startTimer() 74 | } 75 | let indexPath = IndexPath(item: self.currentPage + 1, section: 0) 76 | self.currentPage = self.currentPage + 1 77 | DispatchQueue.main.async { 78 | self.collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: false) 79 | } 80 | 81 | } 82 | 83 | override func viewDidDisappear(_ animated: Bool) { 84 | timer.invalidate() 85 | } 86 | 87 | fileprivate func setupLayout() 88 | { 89 | self.collectionView.backgroundColor = UIColor.clear 90 | self.vwactions.layer.cornerRadius = self.vwactions.frame.size.height / 2 91 | self.vwactions.layer.borderColor = UIColor.lightGray.cgColor 92 | self.vwactions.layer.borderWidth = 0.8 93 | 94 | let layout = self.collectionView.collectionViewLayout as! PUCoverFlowLayout 95 | let padding = 10.0 96 | layout.scrollDirection = .vertical 97 | layout.itemSize = CGSize(width: (self.collectionView.frame.size.width - padding) / 1.5, height: (self.collectionView.frame.size.width - padding) / 1.2 ) 98 | layout.spacingMode = PUCoverFlowLayoutSpacingMode.overlap(visibleOffset: 120) 99 | layout.sideItemScale = 0.8 100 | } 101 | 102 | fileprivate func createItems() -> [Character] { 103 | 104 | let characters = [ 105 | Character(imageName: "https://picsum.photos/id/11/2500/1667", name: "fishes", likecount: "20",commentcount:"10",title: "1.Five tips for a low-carb diet",subtitle: "It’s important to take breaks for mental health.The Pomodoro Technique is a time management system that encourages people",tag: "Physical wellbeing"), 106 | Character(imageName: "https://picsum.photos/id/5/5000/3334", name: "fishes", likecount: "30",commentcount:"13",title: "2.Meditation techniques for beginner",subtitle: "It’s important to take breaks for mental health.The Pomodoro Technique is a time management system that encourages people",tag: "Active days at home"), 107 | Character(imageName: "https://picsum.photos/id/6/5000/3333", name: "fishes", likecount: "210",commentcount:"60",title: "3.Stay fit, run 5k daily",subtitle: "your first time using Carthage in the project, you'll need to go through some additional steps as explained", tag: "Runners"), 108 | Character(imageName: "https://picsum.photos/id/7/4728/3168", name: "fishes", likecount: "740",commentcount:"68",title: "4.Travel together and healthy fitness",subtitle: "It’s important to take breaks for mental health.The Pomodoro Technique is a time management system that encourages people",tag: "Travelling"), 109 | Character(imageName: "https://picsum.photos/id/8/5000/3333", name: "fishes", likecount: "20",commentcount:"150",title: "5.Food choices makes difference in live",subtitle: "It’s important to take breaks for mental health.The Pomodoro Technique is a time management system that encourages people",tag: "Exercising"), 110 | Character(imageName: "https://picsum.photos/id/9/5000/3269", name: "fishes", likecount: "12",commentcount:"6",title: "6.Attempot to recover constarinta of your body",subtitle: "It’s important to take breaks for mental health.The Pomodoro Technique is a time management system that encourages people",tag: "Consultations") 111 | ] 112 | return characters 113 | } 114 | 115 | fileprivate func createShimmerItems() -> [Character] { 116 | 117 | let characters = [ 118 | Character(imageName: "", name: "", likecount: "",commentcount:"",title: "",subtitle: "",tag: ""), 119 | Character(imageName: "", name: "", likecount: "",commentcount:"",title: "",subtitle: "",tag: ""), 120 | Character(imageName: "", name: "", likecount: "",commentcount:"",title: "",subtitle: "",tag: "") 121 | ] 122 | return characters 123 | } 124 | 125 | // MARK: - Card Collection Delegate & DataSource 126 | 127 | func numberOfSections(in collectionView: UICollectionView) -> Int { 128 | return 1 129 | } 130 | 131 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 132 | return Int.max//items.count 133 | } 134 | 135 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 136 | let cell : CarouselCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CarouselCollectionViewCell", for: indexPath) as! CarouselCollectionViewCell 137 | cell.image.layer.masksToBounds = true 138 | cell.image.layer.cornerRadius = 10 139 | cell.image.clipsToBounds = true 140 | let character = items[indexPath.row % items.count ] 141 | cell.lbltitle.text = character.title 142 | cell.lbldescr.text = character.subtitle 143 | cell.lbltag.text = character.tag 144 | if character.imageName != "" 145 | { 146 | cell.image.sd_setImage(with: URL(string: character.imageName), placeholderImage: UIImage(named: character.name), context: .none) 147 | cell.image.backgroundColor = UIColor.clear 148 | self.btnlike.setTitle(character.likecount, for: .normal) 149 | self.btncomment.setTitle(character.commentcount, for: .normal) 150 | self.vwactions.alpha = 1 151 | } 152 | else 153 | { 154 | self.vwactions.alpha = 0 155 | cell.image.image = nil 156 | cell.image.backgroundColor = UIColor.gray 157 | } 158 | UIView.animate(withDuration: 1.0, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: [], animations: { 159 | 160 | cell.layoutIfNeeded() 161 | }) 162 | return cell 163 | } 164 | func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { 165 | 166 | } 167 | 168 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 169 | let character = items[indexPath.row % items.count ] 170 | let alert = UIAlertController(title: character.tag, message: character.subtitle, preferredStyle: .alert) 171 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 172 | present(alert, animated: true, completion: nil) 173 | } 174 | 175 | // MARK: - UIScrollViewDelegate 176 | 177 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 178 | let layout = self.collectionView.collectionViewLayout as! PUCoverFlowLayout 179 | let pageSide = (layout.scrollDirection == .horizontal) ? self.pageSize.width : self.pageSize.height 180 | let offset = (layout.scrollDirection == .horizontal) ? scrollView.contentOffset.x : scrollView.contentOffset.y 181 | currentPage = Int(floor((offset - pageSide / 2) / pageSide) + 1) 182 | timer.invalidate() 183 | startTimer() 184 | 185 | } 186 | //MARK: - Auto Scroll 187 | func startTimer() { 188 | timer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(self.scrollAutomatically), userInfo: nil, repeats: true); 189 | } 190 | 191 | @objc func scrollAutomatically(_ timer1: Timer) 192 | { 193 | let scrollPosition: UICollectionView.ScrollPosition = orientation.isPortrait ? .centeredHorizontally : .centeredHorizontally 194 | if currentPage < Int.max 195 | { 196 | let indexPath = IndexPath(item: currentPage + 1, section: 0) 197 | 198 | self.collectionView.scrollToItem(at: indexPath, at: scrollPosition, animated: true) 199 | currentPage = currentPage + 1 200 | } 201 | else 202 | { 203 | if items.count > 1 204 | { 205 | let indexPath = IndexPath(item: 1, section: 0) 206 | self.collectionView.scrollToItem(at: indexPath, at: scrollPosition, animated: true) 207 | currentPage = 0 208 | } 209 | } 210 | } 211 | //MARK: Orientation 212 | @objc fileprivate func rotationDidChange() { 213 | guard !orientation.isFlat else { return } 214 | let layout = self.collectionView.collectionViewLayout as! PUCoverFlowLayout 215 | let direction: UICollectionView.ScrollDirection = orientation.isPortrait ? .horizontal : .horizontal 216 | layout.scrollDirection = direction 217 | if currentPage > 0 { 218 | let indexPath = IndexPath(item: currentPage, section: 0) 219 | let scrollPosition: UICollectionView.ScrollPosition = orientation.isPortrait ? .centeredHorizontally : .centeredHorizontally 220 | self.collectionView.scrollToItem(at: indexPath, at: scrollPosition, animated: false) 221 | } 222 | } 223 | } 224 | extension UIView 225 | { 226 | func startShimmeringEffect() { 227 | let light = UIColor.white.cgColor 228 | let alpha = UIColor(red: 206/255, green: 10/255, blue: 10/255, alpha: 0.7).cgColor 229 | let gradient = CAGradientLayer() 230 | gradient.frame = CGRect(x: -self.bounds.size.width, y: 0, width: 3 * self.bounds.size.width, height: self.bounds.size.height) 231 | gradient.colors = [light, alpha, light] 232 | gradient.startPoint = CGPoint(x: 0.0, y: 0.5) 233 | gradient.endPoint = CGPoint(x: 1.0,y: 0.525) 234 | gradient.locations = [0.35, 0.50, 0.65] 235 | self.layer.mask = gradient 236 | let animation = CABasicAnimation(keyPath: "locations") 237 | animation.fromValue = [0.0, 0.1, 0.2] 238 | animation.toValue = [0.8, 0.9,1.0] 239 | animation.duration = 1.5 240 | animation.repeatCount = HUGE 241 | gradient.add(animation, forKey: "shimmer") 242 | } 243 | func stopShimmeringEffect() { 244 | self.layer.mask = nil 245 | } 246 | } 247 | 248 | 249 | -------------------------------------------------------------------------------- /PUCoverFlow/Views/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PayalUmraliya/PUCoverflowCarousel/69a7dda08cbe5cd895a64cabb2a2a43cb2468bdb/PUCoverFlow/Views/.DS_Store -------------------------------------------------------------------------------- /PUCoverFlow/Views/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 | -------------------------------------------------------------------------------- /PUCoverFlow/Views/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | PFEncoreSansPro-Book 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 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 67 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 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 | -------------------------------------------------------------------------------- /PUCoverFlow/Views/CarouselCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | PFEncoreSansPro-Regular 12 | 13 | 14 | PFHandbookPro-Bold 15 | 16 | 17 | PFHandbookPro-Light 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 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 71 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # PUCoverflowCarousel 3 | 4 | [![License](https://img.shields.io/cocoapods/l/PUGifLoading.svg?style=flat)](https://github.com/PayalUmraliya/PUCoverflowCarousel/blob/Master/LICENSE) 5 | [![Platform](https://img.shields.io/cocoapods/p/PUGifLoading.svg?style=flat)](https://github.com/PayalUmraliya/PUCoverflowCarousel/blob/Master/LICENSE) 6 | 7 | ### Purpose 8 | 9 | PUCoverflowCarousel is a class designed to simplify the implementation of carousel (paged, scrolling views) on iPhone, iPad.No complex dependency addition needed for this library only single file add in your project and you are ready to use the library. Basically it is carousel-style collection view. It takes care of cell presentation, scaling each cell as the collection view is scrolled. 10 | 11 | ### Video Output 12 | 13 | [Click to watch the video](https://youtube.com/shorts/lf8JIcTV3T4?feature=share) 14 | 15 | [![Watch the video](https://img.youtube.com/vi/lf8JIcTV3T4/sddefault.jpg)](https://youtube.com/shorts/lf8JIcTV3T4?feature=share) 16 | 17 | ## Requirements 18 | 19 | ``` Add PUCoverFlowLayout file in your project and use it wherver you need carousel ``` 20 | 21 | [PUCoverFlowLayout](https://github.com/PayalUmraliya/PUCoverflowCarousel/tree/Master/PUCoverFlow/PUCoverFlowLayout) 22 | 23 | ## License 24 | 25 | The MIT License (MIT) 26 | 27 | Copyright (c) 2023 TheKarma 28 | 29 | ## Author 30 | 31 | Payal Umraliya [behappy78600@gmail.com] 32 | 33 | [LinkedIn](https://in.linkedin.com/in/payal-umraliya-makwana-0354a382) 34 | 35 | ツツツツツツ 36 | --------------------------------------------------------------------------------