├── .gitignore ├── LCGCycleCollectionView.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LCGCycleCollectionView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CUCollectionViewCell.h ├── CUCollectionViewCell.m ├── Info.plist ├── LCGCycleView │ ├── LCGCycleCollectionView.h │ ├── LCGCycleCollectionView.m │ ├── LCGCycleTableView.h │ └── LCGCycleTableView.m ├── ViewController.h ├── ViewController.m └── main.m ├── LCGCycleCollectionViewTests ├── Info.plist └── LCGCycleCollectionViewTests.m ├── LCGCycleCollectionViewUITests ├── Info.plist └── LCGCycleCollectionViewUITests.m ├── README.md └── 预览.gif /.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 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots/**/*.png 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LCGCycleCollectionView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1879B29424B5E94F00ACBF50 /* LCGCycleCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1879B29024B5E94E00ACBF50 /* LCGCycleCollectionView.m */; }; 11 | 1879B29524B5E94F00ACBF50 /* LCGCycleTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1879B29324B5E94F00ACBF50 /* LCGCycleTableView.m */; }; 12 | 900C5F4722672BFC002FA0FE /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F4622672BFC002FA0FE /* AppDelegate.m */; }; 13 | 900C5F4A22672BFC002FA0FE /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F4922672BFC002FA0FE /* ViewController.m */; }; 14 | 900C5F4D22672BFC002FA0FE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900C5F4B22672BFC002FA0FE /* Main.storyboard */; }; 15 | 900C5F4F22672C00002FA0FE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 900C5F4E22672C00002FA0FE /* Assets.xcassets */; }; 16 | 900C5F5222672C00002FA0FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900C5F5022672C00002FA0FE /* LaunchScreen.storyboard */; }; 17 | 900C5F5522672C00002FA0FE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F5422672C00002FA0FE /* main.m */; }; 18 | 900C5F5F22672C00002FA0FE /* LCGCycleCollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F5E22672C00002FA0FE /* LCGCycleCollectionViewTests.m */; }; 19 | 900C5F6A22672C00002FA0FE /* LCGCycleCollectionViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F6922672C00002FA0FE /* LCGCycleCollectionViewUITests.m */; }; 20 | 900C5F7D22672C39002FA0FE /* CUCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 900C5F7B22672C39002FA0FE /* CUCollectionViewCell.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 900C5F5B22672C00002FA0FE /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 900C5F3A22672BFC002FA0FE /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 900C5F4122672BFC002FA0FE; 29 | remoteInfo = LCGCycleCollectionView; 30 | }; 31 | 900C5F6622672C00002FA0FE /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 900C5F3A22672BFC002FA0FE /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 900C5F4122672BFC002FA0FE; 36 | remoteInfo = LCGCycleCollectionView; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 1879B29024B5E94E00ACBF50 /* LCGCycleCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LCGCycleCollectionView.m; sourceTree = ""; }; 42 | 1879B29124B5E94E00ACBF50 /* LCGCycleTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LCGCycleTableView.h; sourceTree = ""; }; 43 | 1879B29224B5E94F00ACBF50 /* LCGCycleCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LCGCycleCollectionView.h; sourceTree = ""; }; 44 | 1879B29324B5E94F00ACBF50 /* LCGCycleTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LCGCycleTableView.m; sourceTree = ""; }; 45 | 900C5F4222672BFC002FA0FE /* LCGCycleCollectionView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LCGCycleCollectionView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 900C5F4522672BFC002FA0FE /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 47 | 900C5F4622672BFC002FA0FE /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 48 | 900C5F4822672BFC002FA0FE /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 49 | 900C5F4922672BFC002FA0FE /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 50 | 900C5F4C22672BFC002FA0FE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | 900C5F4E22672C00002FA0FE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | 900C5F5122672C00002FA0FE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | 900C5F5322672C00002FA0FE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 900C5F5422672C00002FA0FE /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | 900C5F5A22672C00002FA0FE /* LCGCycleCollectionViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LCGCycleCollectionViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 900C5F5E22672C00002FA0FE /* LCGCycleCollectionViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCGCycleCollectionViewTests.m; sourceTree = ""; }; 57 | 900C5F6022672C00002FA0FE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 900C5F6522672C00002FA0FE /* LCGCycleCollectionViewUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LCGCycleCollectionViewUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 900C5F6922672C00002FA0FE /* LCGCycleCollectionViewUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCGCycleCollectionViewUITests.m; sourceTree = ""; }; 60 | 900C5F6B22672C00002FA0FE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 900C5F7B22672C39002FA0FE /* CUCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CUCollectionViewCell.m; sourceTree = ""; }; 62 | 900C5F7C22672C39002FA0FE /* CUCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CUCollectionViewCell.h; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 900C5F3F22672BFC002FA0FE /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 900C5F5722672C00002FA0FE /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | 900C5F6222672C00002FA0FE /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | 900C5F3922672BFC002FA0FE = { 91 | isa = PBXGroup; 92 | children = ( 93 | 900C5F4422672BFC002FA0FE /* LCGCycleCollectionView */, 94 | 900C5F5D22672C00002FA0FE /* LCGCycleCollectionViewTests */, 95 | 900C5F6822672C00002FA0FE /* LCGCycleCollectionViewUITests */, 96 | 900C5F4322672BFC002FA0FE /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | 900C5F4322672BFC002FA0FE /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 900C5F4222672BFC002FA0FE /* LCGCycleCollectionView.app */, 104 | 900C5F5A22672C00002FA0FE /* LCGCycleCollectionViewTests.xctest */, 105 | 900C5F6522672C00002FA0FE /* LCGCycleCollectionViewUITests.xctest */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | 900C5F4422672BFC002FA0FE /* LCGCycleCollectionView */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 900C5F7722672C15002FA0FE /* LCGCycleView */, 114 | 900C5F4522672BFC002FA0FE /* AppDelegate.h */, 115 | 900C5F4622672BFC002FA0FE /* AppDelegate.m */, 116 | 900C5F4822672BFC002FA0FE /* ViewController.h */, 117 | 900C5F4922672BFC002FA0FE /* ViewController.m */, 118 | 900C5F7C22672C39002FA0FE /* CUCollectionViewCell.h */, 119 | 900C5F7B22672C39002FA0FE /* CUCollectionViewCell.m */, 120 | 900C5F4B22672BFC002FA0FE /* Main.storyboard */, 121 | 900C5F4E22672C00002FA0FE /* Assets.xcassets */, 122 | 900C5F5022672C00002FA0FE /* LaunchScreen.storyboard */, 123 | 900C5F5322672C00002FA0FE /* Info.plist */, 124 | 900C5F5422672C00002FA0FE /* main.m */, 125 | ); 126 | path = LCGCycleCollectionView; 127 | sourceTree = ""; 128 | }; 129 | 900C5F5D22672C00002FA0FE /* LCGCycleCollectionViewTests */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 900C5F5E22672C00002FA0FE /* LCGCycleCollectionViewTests.m */, 133 | 900C5F6022672C00002FA0FE /* Info.plist */, 134 | ); 135 | path = LCGCycleCollectionViewTests; 136 | sourceTree = ""; 137 | }; 138 | 900C5F6822672C00002FA0FE /* LCGCycleCollectionViewUITests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 900C5F6922672C00002FA0FE /* LCGCycleCollectionViewUITests.m */, 142 | 900C5F6B22672C00002FA0FE /* Info.plist */, 143 | ); 144 | path = LCGCycleCollectionViewUITests; 145 | sourceTree = ""; 146 | }; 147 | 900C5F7722672C15002FA0FE /* LCGCycleView */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 1879B29224B5E94F00ACBF50 /* LCGCycleCollectionView.h */, 151 | 1879B29024B5E94E00ACBF50 /* LCGCycleCollectionView.m */, 152 | 1879B29124B5E94E00ACBF50 /* LCGCycleTableView.h */, 153 | 1879B29324B5E94F00ACBF50 /* LCGCycleTableView.m */, 154 | ); 155 | path = LCGCycleView; 156 | sourceTree = ""; 157 | }; 158 | /* End PBXGroup section */ 159 | 160 | /* Begin PBXNativeTarget section */ 161 | 900C5F4122672BFC002FA0FE /* LCGCycleCollectionView */ = { 162 | isa = PBXNativeTarget; 163 | buildConfigurationList = 900C5F6E22672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionView" */; 164 | buildPhases = ( 165 | 900C5F3E22672BFC002FA0FE /* Sources */, 166 | 900C5F3F22672BFC002FA0FE /* Frameworks */, 167 | 900C5F4022672BFC002FA0FE /* Resources */, 168 | ); 169 | buildRules = ( 170 | ); 171 | dependencies = ( 172 | ); 173 | name = LCGCycleCollectionView; 174 | productName = LCGCycleCollectionView; 175 | productReference = 900C5F4222672BFC002FA0FE /* LCGCycleCollectionView.app */; 176 | productType = "com.apple.product-type.application"; 177 | }; 178 | 900C5F5922672C00002FA0FE /* LCGCycleCollectionViewTests */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = 900C5F7122672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionViewTests" */; 181 | buildPhases = ( 182 | 900C5F5622672C00002FA0FE /* Sources */, 183 | 900C5F5722672C00002FA0FE /* Frameworks */, 184 | 900C5F5822672C00002FA0FE /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | 900C5F5C22672C00002FA0FE /* PBXTargetDependency */, 190 | ); 191 | name = LCGCycleCollectionViewTests; 192 | productName = LCGCycleCollectionViewTests; 193 | productReference = 900C5F5A22672C00002FA0FE /* LCGCycleCollectionViewTests.xctest */; 194 | productType = "com.apple.product-type.bundle.unit-test"; 195 | }; 196 | 900C5F6422672C00002FA0FE /* LCGCycleCollectionViewUITests */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = 900C5F7422672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionViewUITests" */; 199 | buildPhases = ( 200 | 900C5F6122672C00002FA0FE /* Sources */, 201 | 900C5F6222672C00002FA0FE /* Frameworks */, 202 | 900C5F6322672C00002FA0FE /* Resources */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | 900C5F6722672C00002FA0FE /* PBXTargetDependency */, 208 | ); 209 | name = LCGCycleCollectionViewUITests; 210 | productName = LCGCycleCollectionViewUITests; 211 | productReference = 900C5F6522672C00002FA0FE /* LCGCycleCollectionViewUITests.xctest */; 212 | productType = "com.apple.product-type.bundle.ui-testing"; 213 | }; 214 | /* End PBXNativeTarget section */ 215 | 216 | /* Begin PBXProject section */ 217 | 900C5F3A22672BFC002FA0FE /* Project object */ = { 218 | isa = PBXProject; 219 | attributes = { 220 | LastUpgradeCheck = 1020; 221 | ORGANIZATIONNAME = "李传光"; 222 | TargetAttributes = { 223 | 900C5F4122672BFC002FA0FE = { 224 | CreatedOnToolsVersion = 10.2; 225 | }; 226 | 900C5F5922672C00002FA0FE = { 227 | CreatedOnToolsVersion = 10.2; 228 | TestTargetID = 900C5F4122672BFC002FA0FE; 229 | }; 230 | 900C5F6422672C00002FA0FE = { 231 | CreatedOnToolsVersion = 10.2; 232 | TestTargetID = 900C5F4122672BFC002FA0FE; 233 | }; 234 | }; 235 | }; 236 | buildConfigurationList = 900C5F3D22672BFC002FA0FE /* Build configuration list for PBXProject "LCGCycleCollectionView" */; 237 | compatibilityVersion = "Xcode 9.3"; 238 | developmentRegion = en; 239 | hasScannedForEncodings = 0; 240 | knownRegions = ( 241 | en, 242 | Base, 243 | ); 244 | mainGroup = 900C5F3922672BFC002FA0FE; 245 | productRefGroup = 900C5F4322672BFC002FA0FE /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | 900C5F4122672BFC002FA0FE /* LCGCycleCollectionView */, 250 | 900C5F5922672C00002FA0FE /* LCGCycleCollectionViewTests */, 251 | 900C5F6422672C00002FA0FE /* LCGCycleCollectionViewUITests */, 252 | ); 253 | }; 254 | /* End PBXProject section */ 255 | 256 | /* Begin PBXResourcesBuildPhase section */ 257 | 900C5F4022672BFC002FA0FE /* Resources */ = { 258 | isa = PBXResourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 900C5F5222672C00002FA0FE /* LaunchScreen.storyboard in Resources */, 262 | 900C5F4F22672C00002FA0FE /* Assets.xcassets in Resources */, 263 | 900C5F4D22672BFC002FA0FE /* Main.storyboard in Resources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | 900C5F5822672C00002FA0FE /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | 900C5F6322672C00002FA0FE /* Resources */ = { 275 | isa = PBXResourcesBuildPhase; 276 | buildActionMask = 2147483647; 277 | files = ( 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | /* End PBXResourcesBuildPhase section */ 282 | 283 | /* Begin PBXSourcesBuildPhase section */ 284 | 900C5F3E22672BFC002FA0FE /* Sources */ = { 285 | isa = PBXSourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | 900C5F4A22672BFC002FA0FE /* ViewController.m in Sources */, 289 | 1879B29524B5E94F00ACBF50 /* LCGCycleTableView.m in Sources */, 290 | 900C5F7D22672C39002FA0FE /* CUCollectionViewCell.m in Sources */, 291 | 900C5F5522672C00002FA0FE /* main.m in Sources */, 292 | 1879B29424B5E94F00ACBF50 /* LCGCycleCollectionView.m in Sources */, 293 | 900C5F4722672BFC002FA0FE /* AppDelegate.m in Sources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | 900C5F5622672C00002FA0FE /* Sources */ = { 298 | isa = PBXSourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | 900C5F5F22672C00002FA0FE /* LCGCycleCollectionViewTests.m in Sources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | 900C5F6122672C00002FA0FE /* Sources */ = { 306 | isa = PBXSourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | 900C5F6A22672C00002FA0FE /* LCGCycleCollectionViewUITests.m in Sources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | /* End PBXSourcesBuildPhase section */ 314 | 315 | /* Begin PBXTargetDependency section */ 316 | 900C5F5C22672C00002FA0FE /* PBXTargetDependency */ = { 317 | isa = PBXTargetDependency; 318 | target = 900C5F4122672BFC002FA0FE /* LCGCycleCollectionView */; 319 | targetProxy = 900C5F5B22672C00002FA0FE /* PBXContainerItemProxy */; 320 | }; 321 | 900C5F6722672C00002FA0FE /* PBXTargetDependency */ = { 322 | isa = PBXTargetDependency; 323 | target = 900C5F4122672BFC002FA0FE /* LCGCycleCollectionView */; 324 | targetProxy = 900C5F6622672C00002FA0FE /* PBXContainerItemProxy */; 325 | }; 326 | /* End PBXTargetDependency section */ 327 | 328 | /* Begin PBXVariantGroup section */ 329 | 900C5F4B22672BFC002FA0FE /* Main.storyboard */ = { 330 | isa = PBXVariantGroup; 331 | children = ( 332 | 900C5F4C22672BFC002FA0FE /* Base */, 333 | ); 334 | name = Main.storyboard; 335 | sourceTree = ""; 336 | }; 337 | 900C5F5022672C00002FA0FE /* LaunchScreen.storyboard */ = { 338 | isa = PBXVariantGroup; 339 | children = ( 340 | 900C5F5122672C00002FA0FE /* Base */, 341 | ); 342 | name = LaunchScreen.storyboard; 343 | sourceTree = ""; 344 | }; 345 | /* End PBXVariantGroup section */ 346 | 347 | /* Begin XCBuildConfiguration section */ 348 | 900C5F6C22672C00002FA0FE /* Debug */ = { 349 | isa = XCBuildConfiguration; 350 | buildSettings = { 351 | ALWAYS_SEARCH_USER_PATHS = NO; 352 | CLANG_ANALYZER_NONNULL = YES; 353 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 354 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 355 | CLANG_CXX_LIBRARY = "libc++"; 356 | CLANG_ENABLE_MODULES = YES; 357 | CLANG_ENABLE_OBJC_ARC = YES; 358 | CLANG_ENABLE_OBJC_WEAK = YES; 359 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 360 | CLANG_WARN_BOOL_CONVERSION = YES; 361 | CLANG_WARN_COMMA = YES; 362 | CLANG_WARN_CONSTANT_CONVERSION = YES; 363 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 364 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 365 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 366 | CLANG_WARN_EMPTY_BODY = YES; 367 | CLANG_WARN_ENUM_CONVERSION = YES; 368 | CLANG_WARN_INFINITE_RECURSION = YES; 369 | CLANG_WARN_INT_CONVERSION = YES; 370 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 371 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 372 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 373 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 374 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 375 | CLANG_WARN_STRICT_PROTOTYPES = YES; 376 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 377 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | CODE_SIGN_IDENTITY = "iPhone Developer"; 381 | COPY_PHASE_STRIP = NO; 382 | DEBUG_INFORMATION_FORMAT = dwarf; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | ENABLE_TESTABILITY = YES; 385 | GCC_C_LANGUAGE_STANDARD = gnu11; 386 | GCC_DYNAMIC_NO_PIC = NO; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_OPTIMIZATION_LEVEL = 0; 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 394 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 395 | GCC_WARN_UNDECLARED_SELECTOR = YES; 396 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 397 | GCC_WARN_UNUSED_FUNCTION = YES; 398 | GCC_WARN_UNUSED_VARIABLE = YES; 399 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 400 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 401 | MTL_FAST_MATH = YES; 402 | ONLY_ACTIVE_ARCH = YES; 403 | SDKROOT = iphoneos; 404 | }; 405 | name = Debug; 406 | }; 407 | 900C5F6D22672C00002FA0FE /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ALWAYS_SEARCH_USER_PATHS = NO; 411 | CLANG_ANALYZER_NONNULL = YES; 412 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 413 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 414 | CLANG_CXX_LIBRARY = "libc++"; 415 | CLANG_ENABLE_MODULES = YES; 416 | CLANG_ENABLE_OBJC_ARC = YES; 417 | CLANG_ENABLE_OBJC_WEAK = YES; 418 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_COMMA = YES; 421 | CLANG_WARN_CONSTANT_CONVERSION = YES; 422 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 423 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 424 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 425 | CLANG_WARN_EMPTY_BODY = YES; 426 | CLANG_WARN_ENUM_CONVERSION = YES; 427 | CLANG_WARN_INFINITE_RECURSION = YES; 428 | CLANG_WARN_INT_CONVERSION = YES; 429 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 430 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 437 | CLANG_WARN_UNREACHABLE_CODE = YES; 438 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 439 | CODE_SIGN_IDENTITY = "iPhone Developer"; 440 | COPY_PHASE_STRIP = NO; 441 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 442 | ENABLE_NS_ASSERTIONS = NO; 443 | ENABLE_STRICT_OBJC_MSGSEND = YES; 444 | GCC_C_LANGUAGE_STANDARD = gnu11; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 447 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 448 | GCC_WARN_UNDECLARED_SELECTOR = YES; 449 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 450 | GCC_WARN_UNUSED_FUNCTION = YES; 451 | GCC_WARN_UNUSED_VARIABLE = YES; 452 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 453 | MTL_ENABLE_DEBUG_INFO = NO; 454 | MTL_FAST_MATH = YES; 455 | SDKROOT = iphoneos; 456 | VALIDATE_PRODUCT = YES; 457 | }; 458 | name = Release; 459 | }; 460 | 900C5F6F22672C00002FA0FE /* Debug */ = { 461 | isa = XCBuildConfiguration; 462 | buildSettings = { 463 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 464 | CODE_SIGN_STYLE = Automatic; 465 | INFOPLIST_FILE = LCGCycleCollectionView/Info.plist; 466 | LD_RUNPATH_SEARCH_PATHS = ( 467 | "$(inherited)", 468 | "@executable_path/Frameworks", 469 | ); 470 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionView"; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | TARGETED_DEVICE_FAMILY = "1,2"; 473 | }; 474 | name = Debug; 475 | }; 476 | 900C5F7022672C00002FA0FE /* Release */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 480 | CODE_SIGN_STYLE = Automatic; 481 | INFOPLIST_FILE = LCGCycleCollectionView/Info.plist; 482 | LD_RUNPATH_SEARCH_PATHS = ( 483 | "$(inherited)", 484 | "@executable_path/Frameworks", 485 | ); 486 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionView"; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | TARGETED_DEVICE_FAMILY = "1,2"; 489 | }; 490 | name = Release; 491 | }; 492 | 900C5F7222672C00002FA0FE /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | BUNDLE_LOADER = "$(TEST_HOST)"; 496 | CODE_SIGN_STYLE = Automatic; 497 | INFOPLIST_FILE = LCGCycleCollectionViewTests/Info.plist; 498 | LD_RUNPATH_SEARCH_PATHS = ( 499 | "$(inherited)", 500 | "@executable_path/Frameworks", 501 | "@loader_path/Frameworks", 502 | ); 503 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionViewTests"; 504 | PRODUCT_NAME = "$(TARGET_NAME)"; 505 | TARGETED_DEVICE_FAMILY = "1,2"; 506 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LCGCycleCollectionView.app/LCGCycleCollectionView"; 507 | }; 508 | name = Debug; 509 | }; 510 | 900C5F7322672C00002FA0FE /* Release */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | BUNDLE_LOADER = "$(TEST_HOST)"; 514 | CODE_SIGN_STYLE = Automatic; 515 | INFOPLIST_FILE = LCGCycleCollectionViewTests/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = ( 517 | "$(inherited)", 518 | "@executable_path/Frameworks", 519 | "@loader_path/Frameworks", 520 | ); 521 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionViewTests"; 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | TARGETED_DEVICE_FAMILY = "1,2"; 524 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LCGCycleCollectionView.app/LCGCycleCollectionView"; 525 | }; 526 | name = Release; 527 | }; 528 | 900C5F7522672C00002FA0FE /* Debug */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | CODE_SIGN_STYLE = Automatic; 532 | INFOPLIST_FILE = LCGCycleCollectionViewUITests/Info.plist; 533 | LD_RUNPATH_SEARCH_PATHS = ( 534 | "$(inherited)", 535 | "@executable_path/Frameworks", 536 | "@loader_path/Frameworks", 537 | ); 538 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionViewUITests"; 539 | PRODUCT_NAME = "$(TARGET_NAME)"; 540 | TARGETED_DEVICE_FAMILY = "1,2"; 541 | TEST_TARGET_NAME = LCGCycleCollectionView; 542 | }; 543 | name = Debug; 544 | }; 545 | 900C5F7622672C00002FA0FE /* Release */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | CODE_SIGN_STYLE = Automatic; 549 | INFOPLIST_FILE = LCGCycleCollectionViewUITests/Info.plist; 550 | LD_RUNPATH_SEARCH_PATHS = ( 551 | "$(inherited)", 552 | "@executable_path/Frameworks", 553 | "@loader_path/Frameworks", 554 | ); 555 | PRODUCT_BUNDLE_IDENTIFIER = "-2.LCGCycleCollectionViewUITests"; 556 | PRODUCT_NAME = "$(TARGET_NAME)"; 557 | TARGETED_DEVICE_FAMILY = "1,2"; 558 | TEST_TARGET_NAME = LCGCycleCollectionView; 559 | }; 560 | name = Release; 561 | }; 562 | /* End XCBuildConfiguration section */ 563 | 564 | /* Begin XCConfigurationList section */ 565 | 900C5F3D22672BFC002FA0FE /* Build configuration list for PBXProject "LCGCycleCollectionView" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | 900C5F6C22672C00002FA0FE /* Debug */, 569 | 900C5F6D22672C00002FA0FE /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | 900C5F6E22672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionView" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | 900C5F6F22672C00002FA0FE /* Debug */, 578 | 900C5F7022672C00002FA0FE /* Release */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | 900C5F7122672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionViewTests" */ = { 584 | isa = XCConfigurationList; 585 | buildConfigurations = ( 586 | 900C5F7222672C00002FA0FE /* Debug */, 587 | 900C5F7322672C00002FA0FE /* Release */, 588 | ); 589 | defaultConfigurationIsVisible = 0; 590 | defaultConfigurationName = Release; 591 | }; 592 | 900C5F7422672C00002FA0FE /* Build configuration list for PBXNativeTarget "LCGCycleCollectionViewUITests" */ = { 593 | isa = XCConfigurationList; 594 | buildConfigurations = ( 595 | 900C5F7522672C00002FA0FE /* Debug */, 596 | 900C5F7622672C00002FA0FE /* Release */, 597 | ); 598 | defaultConfigurationIsVisible = 0; 599 | defaultConfigurationName = Release; 600 | }; 601 | /* End XCConfigurationList section */ 602 | }; 603 | rootObject = 900C5F3A22672BFC002FA0FE /* Project object */; 604 | } 605 | -------------------------------------------------------------------------------- /LCGCycleCollectionView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LCGCycleCollectionView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/Assets.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 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /LCGCycleCollectionView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LCGCycleCollectionView/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 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/CUCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // CUCollectionViewCell.h 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface CUCollectionViewCell : UICollectionViewCell 14 | @property(nonatomic ,strong)UILabel * titleLabel ; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/CUCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // CUCollectionViewCell.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import "CUCollectionViewCell.h" 10 | 11 | @implementation CUCollectionViewCell 12 | 13 | -(instancetype)initWithFrame:(CGRect)frame{ 14 | if (self = [super initWithFrame:frame]) { 15 | _titleLabel = [[UILabel alloc]initWithFrame:self.bounds]; 16 | _titleLabel.textAlignment = NSTextAlignmentCenter ; 17 | _titleLabel.font = [UIFont boldSystemFontOfSize:20] ; 18 | _titleLabel.textColor = [UIColor whiteColor]; 19 | [self.contentView addSubview:_titleLabel]; 20 | } 21 | return self ; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/LCGCycleView/LCGCycleCollectionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleCollectionView.h 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | @class LCGCycleCollectionView ; 13 | @protocol LCGCycleCollectionViewDataSource 14 | @required 15 | //返回cell个数 16 | - (NSInteger)cycleCollectionViewCellNumber:(LCGCycleCollectionView *)cycleCollectionView ; 17 | 18 | //返回cell 19 | - (__kindof UICollectionViewCell *)cycleCollectionView:(LCGCycleCollectionView *)cycleCollectionView cellIndex:(NSInteger)cellIndex cellForItemAtIndex:(NSInteger)index; 20 | 21 | @end 22 | 23 | @protocol LCGCycleCollectionViewDelegate 24 | @optional 25 | //cell点击 26 | - (void)cycleCollectionView:(LCGCycleCollectionView *)cycleCollectionView cellIndex:(NSInteger)cellIndex didSelectItemAtIndex:(NSInteger)index; 27 | //cell大小 如果是横向滑动就是item的宽度 如果是竖向滑动就是高度 28 | - (CGFloat)cycleCollectionView:(LCGCycleCollectionView *)cycleCollectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndex:(NSInteger)index; 29 | 30 | @end 31 | 32 | @interface LCGCycleCollectionView : UIView 33 | 34 | @property (nonatomic, weak, nullable) id delegate; 35 | @property (nonatomic, weak, nullable) id dataSource; 36 | 37 | /// item大小 如果是横向滑动就是item的宽度 如果是竖向滑动就是高度 38 | @property (nonatomic ,assign)IBInspectable CGFloat itemSize ; 39 | /// 是否是横向滑动 40 | @property (nonatomic ,assign)IBInspectable BOOL isHorizontal ; 41 | /// item间距 42 | @property (nonatomic ,assign)IBInspectable CGFloat itemSpacing ; 43 | /// 是否是分页滑动,默认是yes,no的话就是平滑滑动 44 | @property (nonatomic ,assign)IBInspectable BOOL pagingEnabled; 45 | //是否自动滑动 46 | @property (nonatomic ,assign)IBInspectable BOOL autoScroll; 47 | //定时器调用间隔 分页滑动 最小为1 48 | @property (nonatomic ,assign)IBInspectable CGFloat timeInterval ; 49 | //每次移动距离 默认0.5 如果是负数 方向相反; 50 | @property (nonatomic ,assign)IBInspectable CGFloat displacement ; 51 | //分页滑动的时候 每次改变的页数的数量 默认为1 52 | @property (nonatomic ,assign)IBInspectable NSUInteger changePageCount ; 53 | //注册UICollectionViewCell 54 | - (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier ; 55 | - (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier; 56 | 57 | - (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forCellIndex:(NSInteger)cellIndex ; 58 | //刷新 59 | -(void)reloadData ; 60 | 61 | //关闭定时器 (在页面消失的时候调用) 62 | - (void)invalidateTimer ; 63 | 64 | //开始定时器 (在页面显示的时候调用) 65 | - (void)setupTimer ; 66 | @end 67 | 68 | NS_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/LCGCycleView/LCGCycleCollectionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleCollectionView.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import "LCGCycleCollectionView.h" 10 | @interface LCGCycleCollectionView () 11 | 12 | @property (nonatomic ,weak) NSTimer *timer; 13 | @property (nonatomic ,strong) UICollectionViewFlowLayout *flowLayout; 14 | //item总个数 15 | @property (nonatomic ,assign) NSInteger totalItemsCount; 16 | //是否可以自动滑动 17 | @property (nonatomic ,assign) BOOL canAutoScroll; 18 | @property (nonatomic ,strong) UICollectionView * collectionView ; 19 | @end 20 | @implementation LCGCycleCollectionView 21 | 22 | //解决当timer释放后 回调scrollViewDidScroll时访问野指针导致崩溃 23 | - (void)dealloc { 24 | self.collectionView.delegate = nil; 25 | self.collectionView.dataSource = nil; 26 | } 27 | 28 | -(UICollectionViewFlowLayout *)flowLayout{ 29 | if (!_flowLayout) { 30 | _flowLayout = [[UICollectionViewFlowLayout alloc] init]; 31 | } 32 | return _flowLayout; 33 | } 34 | 35 | - (void)awakeFromNib{ 36 | [super awakeFromNib]; 37 | } 38 | 39 | -(instancetype)initWithFrame:(CGRect)frame{ 40 | if (self = [super initWithFrame:frame]) { 41 | [self setupUI]; 42 | 43 | self.isHorizontal = YES ; 44 | self.itemSpacing = 5 ; 45 | self.canAutoScroll = YES ; 46 | self.autoScroll = YES ; 47 | self.timeInterval = 1 ; 48 | self.displacement = 0.5 ; 49 | self.changePageCount = 1 ; 50 | } 51 | return self; 52 | } 53 | 54 | -(instancetype)initWithCoder:(NSCoder *)coder{ 55 | if (self = [super initWithCoder:coder]) { 56 | [self setupUI]; 57 | 58 | self.isHorizontal = YES ; 59 | self.itemSpacing = 5 ; 60 | self.canAutoScroll = YES ; 61 | self.autoScroll = YES ; 62 | self.timeInterval = 1 ; 63 | self.displacement = 0.5 ; 64 | self.changePageCount = 1 ; 65 | } 66 | return self; 67 | } 68 | 69 | -(void)setupUI{ 70 | UICollectionView * collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:self.flowLayout]; 71 | collectionView.backgroundColor = [UIColor clearColor]; 72 | collectionView.pagingEnabled = NO; 73 | collectionView.showsHorizontalScrollIndicator = NO; 74 | collectionView.showsVerticalScrollIndicator = NO; 75 | collectionView.dataSource = self; 76 | collectionView.delegate = self; 77 | collectionView.scrollsToTop = NO; 78 | collectionView.frame = self.bounds ; 79 | [self addSubview:collectionView]; 80 | self.collectionView = collectionView ; 81 | 82 | } 83 | 84 | -(void)setItemSize:(CGFloat)itemSize{ 85 | _itemSize = itemSize ; 86 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal){ 87 | self.flowLayout.itemSize = CGSizeMake(itemSize, self.frame.size.height) ; 88 | }else{ 89 | self.flowLayout.itemSize = CGSizeMake(self.frame.size.width, itemSize) ; 90 | } 91 | } 92 | 93 | -(void)setIsHorizontal:(BOOL)isHorizontal{ 94 | _isHorizontal = isHorizontal ; 95 | if (_isHorizontal) { 96 | self.flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal ; 97 | }else{ 98 | self.flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical ; 99 | } 100 | } 101 | 102 | 103 | -(void)reloadData{ 104 | [self invalidateTimer] ; 105 | self.totalItemsCount = [self.dataSource cycleCollectionViewCellNumber:self] ; 106 | 107 | if (self.totalItemsCount<=0) { 108 | [_collectionView reloadData] ; 109 | return ; 110 | } 111 | CGFloat ch = 0 ; 112 | self.canAutoScroll = NO ; 113 | for (int i = 0; i= self.collectionView.frame.size.width) { 122 | self.canAutoScroll = YES ; 123 | break; 124 | } 125 | }else{ 126 | if ([self.delegate respondsToSelector:@selector(cycleCollectionView:layout:sizeForItemAtIndex:)]) { 127 | ch = ch + [self.delegate cycleCollectionView:self layout:self.flowLayout sizeForItemAtIndex:i] ; 128 | }else{ 129 | ch = ch + self.flowLayout.itemSize.height ; 130 | } 131 | if (ch >= self.collectionView.frame.size.height) { 132 | self.canAutoScroll = YES ; 133 | break; 134 | } 135 | } 136 | 137 | } 138 | 139 | [self.collectionView reloadData]; 140 | 141 | if (self.canAutoScroll) { 142 | [self setupTimer]; 143 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(afterDelayHandle) object:nil]; 144 | [self performSelector:@selector(afterDelayHandle) withObject:nil afterDelay:0.2] ; 145 | }else{ 146 | [self invalidateTimer]; 147 | } 148 | } 149 | 150 | -(void)afterDelayHandle{ 151 | //设置初始偏移量 152 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal){ 153 | [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:self.totalItemsCount inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO]; 154 | }else{ 155 | //设置初始偏移量 需在参数设置之后 156 | [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:self.totalItemsCount inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO]; 157 | } 158 | } 159 | 160 | -(void)layoutSubviews{ 161 | [super layoutSubviews]; 162 | self.collectionView.frame = self.bounds ; 163 | if (_isHorizontal) { 164 | self.flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal ; 165 | }else{ 166 | self.flowLayout.scrollDirection = UICollectionViewScrollDirectionVertical ; 167 | } 168 | 169 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal){ 170 | self.flowLayout.itemSize = CGSizeMake(self.itemSize, self.collectionView.frame.size.height) ; 171 | }else{ 172 | self.flowLayout.itemSize = CGSizeMake(self.collectionView.frame.size.width, self.itemSize) ; 173 | } 174 | 175 | [self reloadData] ; 176 | } 177 | 178 | #pragma mark - 插入升序排序 179 | - (NSArray *)inserSort:(NSArray *)array 180 | { 181 | NSMutableArray * returnArray = [NSMutableArray arrayWithArray:array] ; 182 | for (NSInteger i = 1; i < returnArray.count; i ++) { 183 | NSIndexPath *temp = returnArray[i]; 184 | for (NSInteger j = i - 1; j >= 0 && temp.row < [returnArray[j] row]; j --) { 185 | returnArray[j + 1] = returnArray[j]; 186 | returnArray[j] = temp ; 187 | } 188 | } 189 | return returnArray ; 190 | } 191 | 192 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 193 | { 194 | if (self.canAutoScroll) { 195 | [self invalidateTimer]; 196 | } 197 | } 198 | 199 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 200 | { 201 | if (self.canAutoScroll && _autoScroll) { 202 | [self setupTimer]; 203 | } 204 | } 205 | 206 | - (void)setupTimer 207 | { 208 | [self invalidateTimer]; 209 | // 创建定时器前先停止定时器,不然会出现僵尸定时器,导致轮播频率错误 210 | 211 | if (_autoScroll) { 212 | if (_pagingEnabled && _timeInterval<1) { 213 | _timeInterval = 1 ; 214 | } 215 | NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self selector:@selector(_automaticScroll) userInfo:nil repeats:YES]; 216 | _timer = timer; 217 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 218 | } 219 | } 220 | 221 | - (void)invalidateTimer 222 | { 223 | [_timer invalidate]; 224 | _timer = nil; 225 | } 226 | 227 | - (void)_automaticScroll 228 | { 229 | if (_pagingEnabled) { 230 | 231 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) { 232 | if (self.collectionView.contentSize.width >= self.collectionView.frame.size.width) { 233 | NSArray * indexs = [self.collectionView indexPathsForVisibleItems]; 234 | indexs = [self inserSort:indexs] ; 235 | NSIndexPath * currentFirstIndexpath = indexs.firstObject ; 236 | 237 | [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:currentFirstIndexpath.row+self.changePageCount inSection:currentFirstIndexpath.section] atScrollPosition:UICollectionViewScrollPositionLeft animated:YES]; 238 | } 239 | }else{ 240 | if (self.collectionView.contentSize.height >= self.collectionView.frame.size.height) { 241 | NSArray * indexs = [self.collectionView indexPathsForVisibleItems]; 242 | indexs = [self inserSort:indexs] ; 243 | NSIndexPath * currentFirstIndexpath = indexs.firstObject ; 244 | 245 | [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:currentFirstIndexpath.row+self.changePageCount inSection:currentFirstIndexpath.section] atScrollPosition:UICollectionViewScrollPositionTop animated:YES]; 246 | } 247 | } 248 | 249 | }else{ 250 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) { 251 | [self.collectionView setContentOffset:CGPointMake(self.collectionView.contentOffset.x + _displacement, 0)] ; 252 | }else{ 253 | [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.contentOffset.y + _displacement)] ; 254 | } 255 | } 256 | 257 | } 258 | 259 | -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ 260 | if (self.canAutoScroll) { 261 | CGFloat contentoffset = 0; 262 | CGFloat contentValue = 0 ; 263 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) { 264 | contentoffset = self.collectionView.contentOffset.x ; 265 | contentValue = self.collectionView.contentSize.width/3.0 ; 266 | 267 | if (contentoffset>=contentValue*2) { 268 | [self.collectionView setContentOffset:CGPointMake(contentValue ,0 )] ; 269 | }else if(contentoffset <= contentValue - self.collectionView.frame.size.width){ 270 | [self.collectionView setContentOffset:CGPointMake(contentValue * 2 - self.collectionView.frame.size.width , 0)] ; 271 | } 272 | }else{ 273 | contentoffset = self.collectionView.contentOffset.y ; 274 | contentValue = self.collectionView.contentSize.height/3.0 ; 275 | 276 | if (contentoffset>=contentValue*2) { 277 | [self.collectionView setContentOffset:CGPointMake(0 ,contentValue )] ; 278 | }else if(contentoffset <= contentValue - self.collectionView.frame.size.height){ 279 | [self.collectionView setContentOffset:CGPointMake(0 ,contentValue * 2 - self.collectionView.frame.size.height)] ; 280 | } 281 | } 282 | 283 | } 284 | } 285 | 286 | - (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier{ 287 | [self.collectionView registerClass:cellClass forCellWithReuseIdentifier:identifier] ; 288 | } 289 | 290 | - (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier { 291 | [self.collectionView registerNib:nib forCellWithReuseIdentifier:identifier]; 292 | } 293 | 294 | - (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forCellIndex:(NSInteger)cellIndex{ 295 | return [self.collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:cellIndex inSection:0]] ; 296 | } 297 | 298 | -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 299 | if (self.canAutoScroll == NO) { 300 | return self.totalItemsCount ; 301 | } 302 | return self.totalItemsCount * 3 ; 303 | } 304 | 305 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 306 | return [self.dataSource cycleCollectionView:self cellIndex:indexPath.row cellForItemAtIndex:[self indexTransformWithIndex:indexPath]] ; 307 | } 308 | 309 | 310 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ 311 | [collectionView deselectItemAtIndexPath:indexPath animated:NO]; 312 | if ([self.delegate respondsToSelector:@selector(cycleCollectionView:cellIndex:didSelectItemAtIndex:)]) { 313 | [self.delegate cycleCollectionView:self cellIndex:indexPath.row didSelectItemAtIndex:[self indexTransformWithIndex:indexPath]] ; 314 | } 315 | } 316 | 317 | -(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ 318 | 319 | if ([self.delegate respondsToSelector:@selector(cycleCollectionView:layout:sizeForItemAtIndex:)]) { 320 | CGFloat value = [self.delegate cycleCollectionView:self layout:collectionViewLayout sizeForItemAtIndex:[self indexTransformWithIndex:indexPath]]; 321 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal){ 322 | return CGSizeMake(value, collectionView.frame.size.height); 323 | }else{ 324 | return CGSizeMake(collectionView.frame.size.width, value); 325 | } 326 | } 327 | return self.flowLayout.itemSize ; 328 | } 329 | 330 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{ 331 | if (self.flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) { 332 | return _itemSpacing; 333 | } 334 | return 0; 335 | } 336 | 337 | - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{ 338 | if (self.flowLayout.scrollDirection != UICollectionViewScrollDirectionHorizontal) { 339 | return _itemSpacing; 340 | } 341 | return 0; 342 | } 343 | 344 | -(NSInteger)indexTransformWithIndex:(NSIndexPath *)indexPath{ 345 | NSIndexPath * newIndexPath ; 346 | if (self.canAutoScroll == NO) { 347 | newIndexPath = indexPath ; 348 | }else{ 349 | if (self.totalItemsCount*2>indexPath.row && indexPath.row>= self.totalItemsCount) { 350 | newIndexPath = [NSIndexPath indexPathForRow:indexPath.row - self.totalItemsCount inSection:0] ; 351 | }else if(self.totalItemsCount>indexPath.row){ 352 | newIndexPath = indexPath ; 353 | }else{ 354 | newIndexPath = [NSIndexPath indexPathForRow:indexPath.row - self.totalItemsCount * 2 inSection:0] ; 355 | } 356 | } 357 | return newIndexPath.row ; 358 | } 359 | 360 | 361 | /* 362 | // Only override drawRect: if you perform custom drawing. 363 | // An empty implementation adversely affects performance during animation. 364 | - (void)drawRect:(CGRect)rect { 365 | // Drawing code 366 | } 367 | */ 368 | 369 | @end 370 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/LCGCycleView/LCGCycleTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleTableView.h 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/19. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | @class LCGCycleTableView ; 13 | @protocol LCGCycleTableViewDataSource 14 | @required 15 | //返回cell个数 16 | - (NSInteger)cycleTableViewCellNumber:(LCGCycleTableView *)cycleTableView ; 17 | 18 | //返回cell 19 | -(UITableViewCell *)cycleTableView:(LCGCycleTableView *)cycleTableView cellIndex:(NSInteger)cellIndex cellForRowAtIndex:(NSInteger)index ; 20 | 21 | @end 22 | 23 | @protocol LCGCycleTableViewDelegate 24 | @optional 25 | //cell点击 26 | -(void)cycleTableView:(LCGCycleTableView *)cycleTableView cellIndex:(NSInteger)cellIndex didSelectRowAtIndex:(NSInteger)index; 27 | //cell大小 28 | -(CGFloat)cycleTableView:(LCGCycleTableView *)cycleTableView heightForRowAtIndex:(NSInteger)index; 29 | 30 | @end 31 | 32 | @interface LCGCycleTableView : UIView 33 | @property (nonatomic, weak, nullable) id delegate; 34 | @property (nonatomic, weak, nullable) id dataSource; 35 | //是否分页 建议使用分页滑动 36 | @property (nonatomic ,assign)IBInspectable BOOL pagingEnabled; 37 | //是否自动滑动 38 | @property (nonatomic ,assign)IBInspectable BOOL autoScroll; 39 | //定时器调用间隔 分页滑动 最小为1 40 | @property (nonatomic ,assign)IBInspectable CGFloat timeInterval ; 41 | //每次移动距离 默认0.5 如果是负数 方向相反; 42 | @property (nonatomic ,assign)IBInspectable CGFloat displacement ; 43 | //分页滑动的时候 每次改变的页数的数量 默认为1 44 | @property (nonatomic ,assign)IBInspectable NSUInteger changePageCount ; 45 | 46 | - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier ; 47 | 48 | - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier ; 49 | 50 | - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forCellIndex:(NSInteger)cellIndex ; 51 | //刷新 52 | -(void)reloadData ; 53 | 54 | //关闭定时器 (在页面消失的时候调用) 55 | - (void)invalidateTimer ; 56 | 57 | //开始定时器 (在页面显示的时候调用) 58 | - (void)setupTimer ; 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/LCGCycleView/LCGCycleTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleTableView.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/19. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import "LCGCycleTableView.h" 10 | @interface LCGCycleTableView() 11 | 12 | @property (nonatomic ,strong) UITableView * tableView ; 13 | @property (nonatomic ,weak) NSTimer *timer; 14 | //item总个数 15 | @property (nonatomic ,assign) NSInteger totalItemsCount; 16 | //是否可以自动滑动 17 | @property (nonatomic ,assign) BOOL canAutoScroll; 18 | @end 19 | @implementation LCGCycleTableView 20 | 21 | //解决当timer释放后 回调scrollViewDidScroll时访问野指针导致崩溃 22 | - (void)dealloc { 23 | [self invalidateTimer]; 24 | _tableView.delegate = nil; 25 | _tableView.dataSource = nil; 26 | } 27 | 28 | - (void)awakeFromNib{ 29 | [super awakeFromNib] ; 30 | } 31 | 32 | -(instancetype)initWithFrame:(CGRect)frame{ 33 | if (self = [super initWithFrame:frame]) { 34 | [self setUI]; 35 | } 36 | return self ; 37 | } 38 | 39 | -(instancetype)init{ 40 | if (self = [super init]) { 41 | [self setUI]; 42 | } 43 | return self ; 44 | } 45 | 46 | -(instancetype)initWithCoder:(NSCoder *)coder{ 47 | if (self = [super initWithCoder:coder]) { 48 | [self setUI]; 49 | } 50 | return self; 51 | } 52 | 53 | -(void)setUI{ 54 | UITableView * tableView = [[UITableView alloc]initWithFrame:self.bounds style:UITableViewStylePlain]; 55 | if (@available(iOS 9.0, *)) { 56 | tableView.cellLayoutMarginsFollowReadableWidth = NO; 57 | } else { 58 | // Fallback on earlier versions 59 | } 60 | tableView.delegate = self ; 61 | tableView.dataSource = self ; 62 | tableView.backgroundColor = UIColor.clearColor ; 63 | tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 64 | tableView.estimatedRowHeight = 0 ; 65 | tableView.estimatedSectionFooterHeight = 0 ; 66 | tableView.estimatedSectionHeaderHeight = 0 ; 67 | [tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil] ; 68 | [self addSubview:tableView]; 69 | self.tableView = tableView ; 70 | self.canAutoScroll = YES ; 71 | self.autoScroll = YES ; 72 | self.timeInterval = 1 ; 73 | self.displacement = 0.5 ; 74 | self.changePageCount = 1 ; 75 | 76 | } 77 | 78 | -(void)reloadData{ 79 | [self invalidateTimer]; 80 | 81 | self.totalItemsCount = [self.dataSource cycleTableViewCellNumber:self] ; 82 | 83 | if (self.totalItemsCount<=0) { 84 | [_tableView reloadData] ; 85 | return ; 86 | } 87 | CGFloat ch = 0 ; 88 | self.canAutoScroll = NO ; 89 | for (int i = 0; i= self.tableView.frame.size.height) { 96 | self.canAutoScroll = YES ; 97 | break; 98 | } 99 | } 100 | 101 | 102 | if (self.canAutoScroll) { 103 | //设置初始偏移量 需在参数设置之后 104 | [self setupTimer]; 105 | }else{ 106 | [self invalidateTimer]; 107 | } 108 | [self.tableView reloadData]; 109 | } 110 | 111 | -(void)layoutSubviews{ 112 | [super layoutSubviews]; 113 | self.tableView.frame = self.bounds ; 114 | [self reloadData] ; 115 | } 116 | 117 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 118 | { 119 | if (object == self.tableView) { 120 | if ([keyPath isEqualToString:@"contentSize"]) { 121 | CGSize tableViewContentSize = [change[@"new"] CGSizeValue]; 122 | CGSize oldTableViewContentSize = [change[@"old"] CGSizeValue]; 123 | if (tableViewContentSize.height != oldTableViewContentSize.height) { 124 | if (self.canAutoScroll){ 125 | self.tableView.contentOffset = CGPointMake(0, tableViewContentSize.height / 3) ; 126 | } 127 | } 128 | } 129 | } 130 | } 131 | 132 | #pragma mark - 插入升序排序 133 | - (NSArray *)inserSort:(NSArray *)array 134 | { 135 | NSMutableArray * returnArray = [NSMutableArray arrayWithArray:array] ; 136 | for (NSInteger i = 1; i < returnArray.count; i ++) { 137 | NSIndexPath *temp = returnArray[i]; 138 | for (NSInteger j = i - 1; j >= 0 && temp.row < [returnArray[j] row]; j --) { 139 | returnArray[j + 1] = returnArray[j]; 140 | returnArray[j] = temp ; 141 | } 142 | } 143 | return returnArray ; 144 | } 145 | 146 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 147 | { 148 | if (self.canAutoScroll) { 149 | [self invalidateTimer]; 150 | } 151 | } 152 | 153 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 154 | { 155 | if (self.canAutoScroll && self.autoScroll) { 156 | [self setupTimer]; 157 | } 158 | } 159 | 160 | - (void)setupTimer 161 | { 162 | [self invalidateTimer]; 163 | // 创建定时器前先停止定时器,不然会出现僵尸定时器,导致轮播频率错误 164 | if (self.autoScroll) { 165 | if (_pagingEnabled && self.timeInterval<1) { 166 | self.timeInterval = 1 ; 167 | } 168 | NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.timeInterval target:self selector:@selector(_automaticScroll) userInfo:nil repeats:YES]; 169 | _timer = timer; 170 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 171 | } 172 | } 173 | 174 | - (void)invalidateTimer 175 | { 176 | [_timer invalidate]; 177 | _timer = nil; 178 | } 179 | 180 | - (void)_automaticScroll 181 | { 182 | if ([self.tableView numberOfRowsInSection:0] <= 0) { 183 | return; 184 | } 185 | if (_pagingEnabled) { 186 | NSArray * indexs = [self.tableView indexPathsForVisibleRows]; 187 | indexs = [self inserSort:indexs] ; 188 | NSIndexPath * currentFirstIndexpath = indexs.firstObject ; 189 | [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:currentFirstIndexpath.row+self.changePageCount inSection:currentFirstIndexpath.section] atScrollPosition:UITableViewScrollPositionTop animated:YES]; 190 | }else{ 191 | [self.tableView setContentOffset:CGPointMake(0, self.tableView.contentOffset.y + self.displacement)] ; 192 | } 193 | 194 | } 195 | 196 | -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ 197 | if (self.canAutoScroll) { 198 | //实际内容的容量宽度 199 | CGFloat contentH = self.tableView.contentSize.height/3.0 ; 200 | if (self.tableView.contentOffset.y>=contentH * 2) { 201 | [self.tableView setContentOffset:CGPointMake(0 ,contentH )] ; 202 | }else if(self.tableView.contentOffset.y <= contentH - self.tableView.frame.size.height){ 203 | [self.tableView setContentOffset:CGPointMake(0 ,contentH * 2 - self.tableView.frame.size.height)] ; 204 | } 205 | } 206 | } 207 | 208 | - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier{ 209 | [self.tableView registerClass:cellClass forCellReuseIdentifier:identifier] ; 210 | 211 | } 212 | 213 | - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier{ 214 | [self.tableView registerNib:nib forCellReuseIdentifier:identifier] ; 215 | } 216 | 217 | - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forCellIndex:(NSInteger)cellIndex{ 218 | return [self.tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:[NSIndexPath indexPathForRow:cellIndex inSection:0]] ; 219 | } 220 | 221 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 222 | 223 | if (self.canAutoScroll == NO) { 224 | return self.totalItemsCount ; 225 | } 226 | return self.totalItemsCount * 3 ; 227 | } 228 | 229 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 230 | return [self.dataSource cycleTableView:self cellIndex:indexPath.row cellForRowAtIndex:[self indexTransformWithIndex:indexPath]] ; 231 | } 232 | 233 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 234 | if ([self.delegate respondsToSelector:@selector(cycleTableView:heightForRowAtIndex:)]) { 235 | return [self.delegate cycleTableView:self heightForRowAtIndex:[self indexTransformWithIndex:indexPath]]; 236 | }else{ 237 | return 44 ; 238 | } 239 | } 240 | 241 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 242 | if ([self.delegate respondsToSelector:@selector(cycleTableView:cellIndex:didSelectRowAtIndex:)]) { 243 | [self.delegate cycleTableView:self cellIndex:indexPath.row didSelectRowAtIndex:[self indexTransformWithIndex:indexPath]] ; 244 | } 245 | } 246 | 247 | -(NSInteger)indexTransformWithIndex:(NSIndexPath *)indexPath{ 248 | NSIndexPath * newIndexPath ; 249 | if (self.canAutoScroll == NO) { 250 | newIndexPath = indexPath ; 251 | }else{ 252 | if (self.totalItemsCount*2>indexPath.row && indexPath.row>= self.totalItemsCount) { 253 | newIndexPath = [NSIndexPath indexPathForRow:indexPath.row - self.totalItemsCount inSection:0] ; 254 | }else if(self.totalItemsCount>indexPath.row){ 255 | newIndexPath = indexPath ; 256 | }else{ 257 | newIndexPath = [NSIndexPath indexPathForRow:indexPath.row - self.totalItemsCount * 2 inSection:0] ; 258 | } 259 | } 260 | return newIndexPath.row ; 261 | } 262 | 263 | 264 | /* 265 | // Only override drawRect: if you perform custom drawing. 266 | // An empty implementation adversely affects performance during animation. 267 | - (void)drawRect:(CGRect)rect { 268 | // Drawing code 269 | } 270 | */ 271 | 272 | @end 273 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "LCGCycleCollectionView.h" 11 | #import "CUCollectionViewCell.h" 12 | #import "LCGCycleTableView.h" 13 | @interface ViewController () 14 | { 15 | LCGCycleTableView *tableView ; 16 | NSInteger tableViewCount ; 17 | 18 | LCGCycleCollectionView *collectionView ; 19 | NSInteger collectionViewCount ; 20 | 21 | } 22 | 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | 30 | // Do any additional setup after loading the view. 31 | 32 | LCGCycleCollectionView * cv = [[LCGCycleCollectionView alloc]initWithFrame:CGRectMake(10, 100, self.view.frame.size.width - 20, 150)]; 33 | cv.itemSpacing = 20; 34 | cv.itemSize = 100; 35 | cv.isHorizontal = YES ; 36 | cv.delegate = self ; 37 | cv.dataSource = self ; 38 | // cv.autoScroll = NO ; 39 | // cv.displacement = 1 ; 40 | cv.timeInterval = 0.02; 41 | cv.displacement = 1 ; 42 | cv.pagingEnabled = NO ; 43 | cv.changePageCount = 1 ; 44 | cv.tag = 1000 ; 45 | [cv registerClass:[CUCollectionViewCell class] forCellWithReuseIdentifier:@"CUCollectionViewCell"] ; 46 | [self.view addSubview:cv] ; 47 | collectionView = cv ; 48 | collectionViewCount = 50 ; 49 | 50 | 51 | LCGCycleTableView * tv = [[LCGCycleTableView alloc]initWithFrame:CGRectMake(10, 300, self.view.frame.size.width - 20, 120)] ; 52 | tv.delegate = self ; 53 | tv.dataSource = self ; 54 | // cv.autoScroll = NO ; 55 | // cv.displacement = 1 ; 56 | tv.timeInterval = 1; 57 | tv.pagingEnabled = YES ; 58 | tv.changePageCount = 1 ; 59 | tv.tag = 1001 ; 60 | [tv registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"] ; 61 | [self.view addSubview:tv] ; 62 | tableView = tv ; 63 | tableViewCount = 50; 64 | 65 | } 66 | 67 | 68 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 69 | collectionViewCount = arc4random()% 20; 70 | NSLog(@"*-*-*-*-*-**-*-*-*- %ld" , (long)collectionViewCount); 71 | LCGCycleCollectionView * cv = [self.view viewWithTag:1000] ; 72 | [cv reloadData]; 73 | 74 | tableViewCount = arc4random()% 20; 75 | NSLog(@"*-*-*-*-*-**-*-*-*-22 %ld" , (long)tableViewCount); 76 | LCGCycleTableView * tv = [self.view viewWithTag:1001] ; 77 | [tv reloadData] ; 78 | } 79 | 80 | -(void)viewWillAppear:(BOOL)animated{ 81 | [super viewWillAppear:animated]; 82 | LCGCycleCollectionView * cv = [self.view viewWithTag:1000] ; 83 | LCGCycleTableView * tv = [self.view viewWithTag:1001] ; 84 | [cv setupTimer]; 85 | [tv setupTimer]; 86 | } 87 | 88 | -(void)viewDidDisappear:(BOOL)animated{ 89 | [super viewDidDisappear:animated]; 90 | LCGCycleCollectionView * cv = [self.view viewWithTag:1000] ; 91 | LCGCycleTableView * tv = [self.view viewWithTag:1001] ; 92 | [cv invalidateTimer]; 93 | [tv invalidateTimer]; 94 | } 95 | 96 | //LCGCycleCollectionView dataSource 97 | 98 | -(NSInteger)cycleCollectionViewCellNumber:(LCGCycleCollectionView *)cycleCollectionView{ 99 | return collectionViewCount; 100 | } 101 | 102 | - (__kindof UICollectionViewCell *)cycleCollectionView:(LCGCycleCollectionView *)cycleCollectionView cellIndex:(NSInteger)cellIndex cellForItemAtIndex:(NSInteger)index{ 103 | CUCollectionViewCell * cell = [cycleCollectionView dequeueReusableCellWithReuseIdentifier:@"CUCollectionViewCell" forCellIndex:cellIndex]; 104 | cell.backgroundColor = [UIColor blueColor]; 105 | cell.titleLabel.text = [NSString stringWithFormat:@"%ld",(long)index]; 106 | return cell ; 107 | } 108 | 109 | //LCGCycleTableView dataSource 110 | -(NSInteger)cycleTableViewCellNumber:(LCGCycleTableView *)cycleTableView{ 111 | return tableViewCount ; 112 | } 113 | 114 | -(UITableViewCell *)cycleTableView:(LCGCycleTableView *)cycleTableView cellIndex:(NSInteger)cellIndex cellForRowAtIndex:(NSInteger)index{ 115 | UITableViewCell * cell = [cycleTableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forCellIndex:cellIndex]; 116 | if (index%3 == 0) { 117 | cell.backgroundColor = [UIColor redColor] ; 118 | }else if (index%3 == 1){ 119 | cell.backgroundColor = [UIColor greenColor] ; 120 | }else{ 121 | cell.backgroundColor = [UIColor blueColor] ; 122 | } 123 | cell.textLabel.textAlignment = NSTextAlignmentCenter ; 124 | cell.textLabel.font = [UIFont boldSystemFontOfSize:20] ; 125 | cell.textLabel.textColor = [UIColor whiteColor]; 126 | cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)index]; 127 | return cell ; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /LCGCycleCollectionView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LCGCycleCollectionView 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LCGCycleCollectionViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LCGCycleCollectionViewTests/LCGCycleCollectionViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleCollectionViewTests.m 3 | // LCGCycleCollectionViewTests 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LCGCycleCollectionViewTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LCGCycleCollectionViewTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /LCGCycleCollectionViewUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LCGCycleCollectionViewUITests/LCGCycleCollectionViewUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LCGCycleCollectionViewUITests.m 3 | // LCGCycleCollectionViewUITests 4 | // 5 | // Created by 李传光 on 2019/4/17. 6 | // Copyright © 2019 李传光. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LCGCycleCollectionViewUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LCGCycleCollectionViewUITests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | 20 | // In UI tests it is usually best to stop immediately when a failure occurs. 21 | self.continueAfterFailure = NO; 22 | 23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 24 | [[[XCUIApplication alloc] init] launch]; 25 | 26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | } 32 | 33 | - (void)testExample { 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LCGCycleView 2 | 一个轻量级无限轮播的CollectionView和tableview,可以方便的设置自己的cell和数据源,可以自定义各种跑马灯,或者轮播效果。基于UICollectionView,UITableview的封装。 3 | 通过设置pagingEnabled可以实现分页滚动或者连续滚动效果 4 | displacement和timeInterval控制滑动速度 5 | ![预览图加载失败](https://github.com/xiaolisv1/LCGCycleView/blob/master/%E9%A2%84%E8%A7%88.gif) 6 | 7 | ## usege demo 8 | * init 9 | ```objc 10 | //-----collectionView 类型 11 | LCGCycleCollectionView * cv = [[LCGCycleCollectionView alloc]initWithFrame:CGRectMake(10, 100, self.view.frame.size.width - 20, 150)]; 12 | cv.itemSpacing = 20; 13 | cv.itemSize = 100; 14 | cv.isHorizontal = YES ; 15 | cv.delegate = self ; 16 | cv.dataSource = self ; 17 | // cv.autoScroll = NO ; 18 | // cv.displacement = 1 ; 19 | cv.timeInterval = 0.02; 20 | cv.displacement = 1 ; 21 | cv.pagingEnabled = NO ; 22 | cv.changePageCount = 1 ; 23 | cv.tag = 1000 ; 24 | [cv registerClass:[CUCollectionViewCell class] forCellWithReuseIdentifier:@"CUCollectionViewCell"] ; 25 | [self.view addSubview:cv] ; 26 | 27 | //-----tableView 类型 28 | LCGCycleTableView * tv = [[LCGCycleTableView alloc]initWithFrame:CGRectMake(10, 300, self.view.frame.size.width - 20, 120)] ; 29 | tv.delegate = self ; 30 | tv.dataSource = self ; 31 | // cv.autoScroll = NO ; 32 | // cv.displacement = 1 ; 33 | tv.timeInterval = 1; 34 | tv.pagingEnabled = YES ; 35 | tv.changePageCount = 1 ; 36 | [tv registerClass:[UITableViewCell class] forCellReuseIdentifier:@"UITableViewCell"] ; 37 | [self.view addSubview:tv] ; 38 | ``` 39 | ### 实现相关代理,返回自己的cell即可 40 | * delegate 41 | ```objc 42 | //LCGCycleCollectionView dataSource 43 | -(NSInteger)cycleCollectionViewCellNumber:(LCGCycleCollectionView *)cycleCollectionView{ 44 | return collectionViewCount; 45 | } 46 | 47 | - (__kindof UICollectionViewCell *)cycleCollectionView:(LCGCycleCollectionView *)cycleCollectionView cellIndex:(NSInteger)cellIndex cellForItemAtIndex:(NSInteger)index{ 48 | CUCollectionViewCell * cell = [cycleCollectionView dequeueReusableCellWithReuseIdentifier:@"CUCollectionViewCell" forCellIndex:cellIndex]; 49 | cell.backgroundColor = [UIColor blueColor]; 50 | cell.titleLabel.text = [NSString stringWithFormat:@"%ld",(long)index]; 51 | return cell ; 52 | } 53 | //LCGCycleTableView dataSource 54 | -(NSInteger)cycleTableViewCellNumber:(LCGCycleTableView *)cycleTableView{ 55 | return tableViewCount ; 56 | } 57 | 58 | -(UITableViewCell *)cycleTableView:(LCGCycleTableView *)cycleTableView cellIndex:(NSInteger)cellIndex cellForRowAtIndex:(NSInteger)index{ 59 | UITableViewCell * cell = [cycleTableView dequeueReusableCellWithIdentifier:@"UITableViewCell" forCellIndex:cellIndex]; 60 | if (index%3 == 0) { 61 | cell.backgroundColor = [UIColor redColor] ; 62 | }else if (index%3 == 1){ 63 | cell.backgroundColor = [UIColor greenColor] ; 64 | }else{ 65 | cell.backgroundColor = [UIColor blueColor] ; 66 | } 67 | cell.textLabel.textAlignment = NSTextAlignmentCenter ; 68 | cell.textLabel.font = [UIFont boldSystemFontOfSize:20] ; 69 | cell.textLabel.textColor = [UIColor whiteColor]; 70 | cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)index]; 71 | return cell ; 72 | } 73 | ``` 74 | ### Contact 75 | if you find bug,please pull reqeust me
76 | -------------------------------------------------------------------------------- /预览.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaolisv1/LCGCycleView/3c437f2f0ecd7d2e5addb24ff5f8dace2e3bceef/预览.gif --------------------------------------------------------------------------------