├── .DS_Store ├── README.md ├── XTLoopScroll.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── tutu.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── tutu.xcuserdatad │ └── xcschemes │ ├── XTLoopScroll.xcscheme │ └── xcschememanagement.plist ├── XTLoopScroll ├── .DS_Store ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── 1.imageset │ │ ├── 1.png │ │ └── Contents.json │ ├── 2.imageset │ │ ├── 2.png │ │ └── Contents.json │ ├── 3.imageset │ │ ├── 3.png │ │ └── Contents.json │ ├── 4.imageset │ │ ├── 4.png │ │ └── Contents.json │ ├── 5.imageset │ │ ├── 5.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-60@2x.png │ │ ├── Icon-60@3x.png │ │ ├── Icon-76.png │ │ ├── Icon-76@2x.png │ │ ├── Icon-Small.png │ │ ├── Icon-Small@2x-1.png │ │ ├── Icon-Small@2x.png │ │ ├── Icon-Small@3x.png │ │ ├── Icon-Spotlight-40.png │ │ ├── Icon-Spotlight-40@2x-1.png │ │ ├── Icon-Spotlight-40@2x.png │ │ └── Icon-Spotlight-40@3x.png │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── HWWeakerTimer │ ├── HWWeakTimer.h │ └── HWWeakTimer.m ├── Info.plist ├── NSTimer+Addition.h ├── NSTimer+Addition.m ├── ViewController.h ├── ViewController.m ├── XTLoopScroll │ ├── XTLoopScrollView.h │ └── XTLoopScrollView.m └── main.m ├── XTLoopScrollTests ├── Info.plist └── XTLoopScrollTests.m └── XTLoopScrollUITests ├── Info.plist └── XTLoopScrollUITests.m /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XTLoopScroll 2 | iOS auto Loop scrollview 3 | 4 | ###HOW TO USE IT ? http://www.jianshu.com/p/a43ffcf666d9 5 | 6 | 1自动轮播 7 | 2点击监听回调当前图片 8 | 3手动滑动后重新计算轮播的开始时间, 良好的用户体验 9 | 10 | 11 | XTLoopScrollView *loopScroll = [[XTLoopScrollView alloc] initWithFrame:rect 12 | andImageList:@[@"1",@"2",@"3",@"4",@"5"] 13 | canLoop:YES 14 | duration:5.0] ; 15 | 16 | loopScroll.color_pageControl = [UIColor colorWithRed:250.0/255.0 green:219/255.0 blue:249/255.0 alpha:1] ; 17 | loopScroll.color_currentPageControl = [UIColor redColor] ; 18 | 19 | [self.view addSubview:loopScroll] ; 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /XTLoopScroll.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D74145AE1BE3506100053E40 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145AD1BE3506100053E40 /* main.m */; }; 11 | D74145B11BE3506100053E40 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145B01BE3506100053E40 /* AppDelegate.m */; }; 12 | D74145B41BE3506100053E40 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145B31BE3506100053E40 /* ViewController.m */; }; 13 | D74145B71BE3506100053E40 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74145B51BE3506100053E40 /* Main.storyboard */; }; 14 | D74145B91BE3506100053E40 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D74145B81BE3506100053E40 /* Assets.xcassets */; }; 15 | D74145BC1BE3506100053E40 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74145BA1BE3506100053E40 /* LaunchScreen.storyboard */; }; 16 | D74145C71BE3506300053E40 /* XTLoopScrollTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145C61BE3506300053E40 /* XTLoopScrollTests.m */; }; 17 | D74145D21BE3506300053E40 /* XTLoopScrollUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145D11BE3506300053E40 /* XTLoopScrollUITests.m */; }; 18 | D74145E11BE35DB100053E40 /* XTLoopScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D74145E01BE35DB100053E40 /* XTLoopScrollView.m */; }; 19 | D7886D701D9236CC003D6D57 /* HWWeakTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = D7886D6F1D9236CC003D6D57 /* HWWeakTimer.m */; }; 20 | D796FDC71BE7719100E8BCD2 /* NSTimer+Addition.m in Sources */ = {isa = PBXBuildFile; fileRef = D796FDC61BE7719100E8BCD2 /* NSTimer+Addition.m */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | D74145C31BE3506300053E40 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = D74145A11BE3506100053E40 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = D74145A81BE3506100053E40; 29 | remoteInfo = XTLoopScroll; 30 | }; 31 | D74145CE1BE3506300053E40 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = D74145A11BE3506100053E40 /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = D74145A81BE3506100053E40; 36 | remoteInfo = XTLoopScroll; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | D74145A91BE3506100053E40 /* XTLoopScroll.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XTLoopScroll.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | D74145AD1BE3506100053E40 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 43 | D74145AF1BE3506100053E40 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 44 | D74145B01BE3506100053E40 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 45 | D74145B21BE3506100053E40 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 46 | D74145B31BE3506100053E40 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 47 | D74145B61BE3506100053E40 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 48 | D74145B81BE3506100053E40 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 49 | D74145BB1BE3506100053E40 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 50 | D74145BD1BE3506100053E40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | D74145C21BE3506300053E40 /* XTLoopScrollTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XTLoopScrollTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | D74145C61BE3506300053E40 /* XTLoopScrollTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XTLoopScrollTests.m; sourceTree = ""; }; 53 | D74145C81BE3506300053E40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | D74145CD1BE3506300053E40 /* XTLoopScrollUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = XTLoopScrollUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | D74145D11BE3506300053E40 /* XTLoopScrollUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XTLoopScrollUITests.m; sourceTree = ""; }; 56 | D74145D31BE3506300053E40 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | D74145DF1BE35DB100053E40 /* XTLoopScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XTLoopScrollView.h; path = XTLoopScroll/XTLoopScrollView.h; sourceTree = ""; }; 58 | D74145E01BE35DB100053E40 /* XTLoopScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XTLoopScrollView.m; path = XTLoopScroll/XTLoopScrollView.m; sourceTree = ""; }; 59 | D7886D6E1D9236CC003D6D57 /* HWWeakTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWWeakTimer.h; sourceTree = ""; }; 60 | D7886D6F1D9236CC003D6D57 /* HWWeakTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HWWeakTimer.m; sourceTree = ""; }; 61 | D796FDC51BE7719100E8BCD2 /* NSTimer+Addition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTimer+Addition.h"; sourceTree = ""; }; 62 | D796FDC61BE7719100E8BCD2 /* NSTimer+Addition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTimer+Addition.m"; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | D74145A61BE3506100053E40 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | D74145BF1BE3506300053E40 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | D74145CA1BE3506300053E40 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | /* End PBXFrameworksBuildPhase section */ 88 | 89 | /* Begin PBXGroup section */ 90 | D74145A01BE3506100053E40 = { 91 | isa = PBXGroup; 92 | children = ( 93 | D74145AB1BE3506100053E40 /* XTLoopScroll */, 94 | D74145C51BE3506300053E40 /* XTLoopScrollTests */, 95 | D74145D01BE3506300053E40 /* XTLoopScrollUITests */, 96 | D74145AA1BE3506100053E40 /* Products */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | D74145AA1BE3506100053E40 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | D74145A91BE3506100053E40 /* XTLoopScroll.app */, 104 | D74145C21BE3506300053E40 /* XTLoopScrollTests.xctest */, 105 | D74145CD1BE3506300053E40 /* XTLoopScrollUITests.xctest */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | D74145AB1BE3506100053E40 /* XTLoopScroll */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | D74145AF1BE3506100053E40 /* AppDelegate.h */, 114 | D74145B01BE3506100053E40 /* AppDelegate.m */, 115 | D74145B21BE3506100053E40 /* ViewController.h */, 116 | D74145B31BE3506100053E40 /* ViewController.m */, 117 | D7886D6D1D9236CC003D6D57 /* HWWeakerTimer */, 118 | D796FDC51BE7719100E8BCD2 /* NSTimer+Addition.h */, 119 | D796FDC61BE7719100E8BCD2 /* NSTimer+Addition.m */, 120 | D74145E21BE35DC300053E40 /* XTLoopScroll */, 121 | D74145B51BE3506100053E40 /* Main.storyboard */, 122 | D74145B81BE3506100053E40 /* Assets.xcassets */, 123 | D74145BA1BE3506100053E40 /* LaunchScreen.storyboard */, 124 | D74145BD1BE3506100053E40 /* Info.plist */, 125 | D74145AC1BE3506100053E40 /* Supporting Files */, 126 | ); 127 | path = XTLoopScroll; 128 | sourceTree = ""; 129 | }; 130 | D74145AC1BE3506100053E40 /* Supporting Files */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | D74145AD1BE3506100053E40 /* main.m */, 134 | ); 135 | name = "Supporting Files"; 136 | sourceTree = ""; 137 | }; 138 | D74145C51BE3506300053E40 /* XTLoopScrollTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | D74145C61BE3506300053E40 /* XTLoopScrollTests.m */, 142 | D74145C81BE3506300053E40 /* Info.plist */, 143 | ); 144 | path = XTLoopScrollTests; 145 | sourceTree = ""; 146 | }; 147 | D74145D01BE3506300053E40 /* XTLoopScrollUITests */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | D74145D11BE3506300053E40 /* XTLoopScrollUITests.m */, 151 | D74145D31BE3506300053E40 /* Info.plist */, 152 | ); 153 | path = XTLoopScrollUITests; 154 | sourceTree = ""; 155 | }; 156 | D74145E21BE35DC300053E40 /* XTLoopScroll */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | D74145DF1BE35DB100053E40 /* XTLoopScrollView.h */, 160 | D74145E01BE35DB100053E40 /* XTLoopScrollView.m */, 161 | ); 162 | name = XTLoopScroll; 163 | sourceTree = ""; 164 | }; 165 | D7886D6D1D9236CC003D6D57 /* HWWeakerTimer */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | D7886D6E1D9236CC003D6D57 /* HWWeakTimer.h */, 169 | D7886D6F1D9236CC003D6D57 /* HWWeakTimer.m */, 170 | ); 171 | path = HWWeakerTimer; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXGroup section */ 175 | 176 | /* Begin PBXNativeTarget section */ 177 | D74145A81BE3506100053E40 /* XTLoopScroll */ = { 178 | isa = PBXNativeTarget; 179 | buildConfigurationList = D74145D61BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScroll" */; 180 | buildPhases = ( 181 | D74145A51BE3506100053E40 /* Sources */, 182 | D74145A61BE3506100053E40 /* Frameworks */, 183 | D74145A71BE3506100053E40 /* Resources */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = XTLoopScroll; 190 | productName = XTLoopScroll; 191 | productReference = D74145A91BE3506100053E40 /* XTLoopScroll.app */; 192 | productType = "com.apple.product-type.application"; 193 | }; 194 | D74145C11BE3506300053E40 /* XTLoopScrollTests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = D74145D91BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScrollTests" */; 197 | buildPhases = ( 198 | D74145BE1BE3506300053E40 /* Sources */, 199 | D74145BF1BE3506300053E40 /* Frameworks */, 200 | D74145C01BE3506300053E40 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | D74145C41BE3506300053E40 /* PBXTargetDependency */, 206 | ); 207 | name = XTLoopScrollTests; 208 | productName = XTLoopScrollTests; 209 | productReference = D74145C21BE3506300053E40 /* XTLoopScrollTests.xctest */; 210 | productType = "com.apple.product-type.bundle.unit-test"; 211 | }; 212 | D74145CC1BE3506300053E40 /* XTLoopScrollUITests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = D74145DC1BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScrollUITests" */; 215 | buildPhases = ( 216 | D74145C91BE3506300053E40 /* Sources */, 217 | D74145CA1BE3506300053E40 /* Frameworks */, 218 | D74145CB1BE3506300053E40 /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | D74145CF1BE3506300053E40 /* PBXTargetDependency */, 224 | ); 225 | name = XTLoopScrollUITests; 226 | productName = XTLoopScrollUITests; 227 | productReference = D74145CD1BE3506300053E40 /* XTLoopScrollUITests.xctest */; 228 | productType = "com.apple.product-type.bundle.ui-testing"; 229 | }; 230 | /* End PBXNativeTarget section */ 231 | 232 | /* Begin PBXProject section */ 233 | D74145A11BE3506100053E40 /* Project object */ = { 234 | isa = PBXProject; 235 | attributes = { 236 | LastUpgradeCheck = 0700; 237 | ORGANIZATIONNAME = teason; 238 | TargetAttributes = { 239 | D74145A81BE3506100053E40 = { 240 | CreatedOnToolsVersion = 7.0; 241 | }; 242 | D74145C11BE3506300053E40 = { 243 | CreatedOnToolsVersion = 7.0; 244 | TestTargetID = D74145A81BE3506100053E40; 245 | }; 246 | D74145CC1BE3506300053E40 = { 247 | CreatedOnToolsVersion = 7.0; 248 | TestTargetID = D74145A81BE3506100053E40; 249 | }; 250 | }; 251 | }; 252 | buildConfigurationList = D74145A41BE3506100053E40 /* Build configuration list for PBXProject "XTLoopScroll" */; 253 | compatibilityVersion = "Xcode 3.2"; 254 | developmentRegion = English; 255 | hasScannedForEncodings = 0; 256 | knownRegions = ( 257 | en, 258 | Base, 259 | ); 260 | mainGroup = D74145A01BE3506100053E40; 261 | productRefGroup = D74145AA1BE3506100053E40 /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | D74145A81BE3506100053E40 /* XTLoopScroll */, 266 | D74145C11BE3506300053E40 /* XTLoopScrollTests */, 267 | D74145CC1BE3506300053E40 /* XTLoopScrollUITests */, 268 | ); 269 | }; 270 | /* End PBXProject section */ 271 | 272 | /* Begin PBXResourcesBuildPhase section */ 273 | D74145A71BE3506100053E40 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | D74145BC1BE3506100053E40 /* LaunchScreen.storyboard in Resources */, 278 | D74145B91BE3506100053E40 /* Assets.xcassets in Resources */, 279 | D74145B71BE3506100053E40 /* Main.storyboard in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | D74145C01BE3506300053E40 /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | D74145CB1BE3506300053E40 /* Resources */ = { 291 | isa = PBXResourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | /* End PBXResourcesBuildPhase section */ 298 | 299 | /* Begin PBXSourcesBuildPhase section */ 300 | D74145A51BE3506100053E40 /* Sources */ = { 301 | isa = PBXSourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | D7886D701D9236CC003D6D57 /* HWWeakTimer.m in Sources */, 305 | D74145B41BE3506100053E40 /* ViewController.m in Sources */, 306 | D74145E11BE35DB100053E40 /* XTLoopScrollView.m in Sources */, 307 | D74145B11BE3506100053E40 /* AppDelegate.m in Sources */, 308 | D796FDC71BE7719100E8BCD2 /* NSTimer+Addition.m in Sources */, 309 | D74145AE1BE3506100053E40 /* main.m in Sources */, 310 | ); 311 | runOnlyForDeploymentPostprocessing = 0; 312 | }; 313 | D74145BE1BE3506300053E40 /* Sources */ = { 314 | isa = PBXSourcesBuildPhase; 315 | buildActionMask = 2147483647; 316 | files = ( 317 | D74145C71BE3506300053E40 /* XTLoopScrollTests.m in Sources */, 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | }; 321 | D74145C91BE3506300053E40 /* Sources */ = { 322 | isa = PBXSourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | D74145D21BE3506300053E40 /* XTLoopScrollUITests.m in Sources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXSourcesBuildPhase section */ 330 | 331 | /* Begin PBXTargetDependency section */ 332 | D74145C41BE3506300053E40 /* PBXTargetDependency */ = { 333 | isa = PBXTargetDependency; 334 | target = D74145A81BE3506100053E40 /* XTLoopScroll */; 335 | targetProxy = D74145C31BE3506300053E40 /* PBXContainerItemProxy */; 336 | }; 337 | D74145CF1BE3506300053E40 /* PBXTargetDependency */ = { 338 | isa = PBXTargetDependency; 339 | target = D74145A81BE3506100053E40 /* XTLoopScroll */; 340 | targetProxy = D74145CE1BE3506300053E40 /* PBXContainerItemProxy */; 341 | }; 342 | /* End PBXTargetDependency section */ 343 | 344 | /* Begin PBXVariantGroup section */ 345 | D74145B51BE3506100053E40 /* Main.storyboard */ = { 346 | isa = PBXVariantGroup; 347 | children = ( 348 | D74145B61BE3506100053E40 /* Base */, 349 | ); 350 | name = Main.storyboard; 351 | sourceTree = ""; 352 | }; 353 | D74145BA1BE3506100053E40 /* LaunchScreen.storyboard */ = { 354 | isa = PBXVariantGroup; 355 | children = ( 356 | D74145BB1BE3506100053E40 /* Base */, 357 | ); 358 | name = LaunchScreen.storyboard; 359 | sourceTree = ""; 360 | }; 361 | /* End PBXVariantGroup section */ 362 | 363 | /* Begin XCBuildConfiguration section */ 364 | D74145D41BE3506300053E40 /* Debug */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ALWAYS_SEARCH_USER_PATHS = NO; 368 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 369 | CLANG_CXX_LIBRARY = "libc++"; 370 | CLANG_ENABLE_MODULES = YES; 371 | CLANG_ENABLE_OBJC_ARC = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 379 | CLANG_WARN_UNREACHABLE_CODE = YES; 380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 381 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 382 | COPY_PHASE_STRIP = NO; 383 | DEBUG_INFORMATION_FORMAT = dwarf; 384 | ENABLE_STRICT_OBJC_MSGSEND = YES; 385 | ENABLE_TESTABILITY = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_NO_COMMON_BLOCKS = YES; 389 | GCC_OPTIMIZATION_LEVEL = 0; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 395 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 396 | GCC_WARN_UNDECLARED_SELECTOR = YES; 397 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 398 | GCC_WARN_UNUSED_FUNCTION = YES; 399 | GCC_WARN_UNUSED_VARIABLE = YES; 400 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 401 | MTL_ENABLE_DEBUG_INFO = YES; 402 | ONLY_ACTIVE_ARCH = YES; 403 | SDKROOT = iphoneos; 404 | TARGETED_DEVICE_FAMILY = "1,2"; 405 | }; 406 | name = Debug; 407 | }; 408 | D74145D51BE3506300053E40 /* Release */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | ALWAYS_SEARCH_USER_PATHS = NO; 412 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 413 | CLANG_CXX_LIBRARY = "libc++"; 414 | CLANG_ENABLE_MODULES = YES; 415 | CLANG_ENABLE_OBJC_ARC = YES; 416 | CLANG_WARN_BOOL_CONVERSION = YES; 417 | CLANG_WARN_CONSTANT_CONVERSION = YES; 418 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 419 | CLANG_WARN_EMPTY_BODY = YES; 420 | CLANG_WARN_ENUM_CONVERSION = YES; 421 | CLANG_WARN_INT_CONVERSION = YES; 422 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 423 | CLANG_WARN_UNREACHABLE_CODE = YES; 424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 425 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 426 | COPY_PHASE_STRIP = NO; 427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 428 | ENABLE_NS_ASSERTIONS = NO; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | GCC_C_LANGUAGE_STANDARD = gnu99; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 433 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 434 | GCC_WARN_UNDECLARED_SELECTOR = YES; 435 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 436 | GCC_WARN_UNUSED_FUNCTION = YES; 437 | GCC_WARN_UNUSED_VARIABLE = YES; 438 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 439 | MTL_ENABLE_DEBUG_INFO = NO; 440 | SDKROOT = iphoneos; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | VALIDATE_PRODUCT = YES; 443 | }; 444 | name = Release; 445 | }; 446 | D74145D71BE3506300053E40 /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | INFOPLIST_FILE = XTLoopScroll/Info.plist; 451 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 452 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScroll; 453 | PRODUCT_NAME = "$(TARGET_NAME)"; 454 | }; 455 | name = Debug; 456 | }; 457 | D74145D81BE3506300053E40 /* Release */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 461 | INFOPLIST_FILE = XTLoopScroll/Info.plist; 462 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 463 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScroll; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | }; 466 | name = Release; 467 | }; 468 | D74145DA1BE3506300053E40 /* Debug */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | BUNDLE_LOADER = "$(TEST_HOST)"; 472 | INFOPLIST_FILE = XTLoopScrollTests/Info.plist; 473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 474 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScrollTests; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XTLoopScroll.app/XTLoopScroll"; 477 | }; 478 | name = Debug; 479 | }; 480 | D74145DB1BE3506300053E40 /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | BUNDLE_LOADER = "$(TEST_HOST)"; 484 | INFOPLIST_FILE = XTLoopScrollTests/Info.plist; 485 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 486 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScrollTests; 487 | PRODUCT_NAME = "$(TARGET_NAME)"; 488 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/XTLoopScroll.app/XTLoopScroll"; 489 | }; 490 | name = Release; 491 | }; 492 | D74145DD1BE3506300053E40 /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | INFOPLIST_FILE = XTLoopScrollUITests/Info.plist; 496 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 497 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScrollUITests; 498 | PRODUCT_NAME = "$(TARGET_NAME)"; 499 | TEST_TARGET_NAME = XTLoopScroll; 500 | USES_XCTRUNNER = YES; 501 | }; 502 | name = Debug; 503 | }; 504 | D74145DE1BE3506300053E40 /* Release */ = { 505 | isa = XCBuildConfiguration; 506 | buildSettings = { 507 | INFOPLIST_FILE = XTLoopScrollUITests/Info.plist; 508 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 509 | PRODUCT_BUNDLE_IDENTIFIER = zzz.XTLoopScrollUITests; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | TEST_TARGET_NAME = XTLoopScroll; 512 | USES_XCTRUNNER = YES; 513 | }; 514 | name = Release; 515 | }; 516 | /* End XCBuildConfiguration section */ 517 | 518 | /* Begin XCConfigurationList section */ 519 | D74145A41BE3506100053E40 /* Build configuration list for PBXProject "XTLoopScroll" */ = { 520 | isa = XCConfigurationList; 521 | buildConfigurations = ( 522 | D74145D41BE3506300053E40 /* Debug */, 523 | D74145D51BE3506300053E40 /* Release */, 524 | ); 525 | defaultConfigurationIsVisible = 0; 526 | defaultConfigurationName = Release; 527 | }; 528 | D74145D61BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScroll" */ = { 529 | isa = XCConfigurationList; 530 | buildConfigurations = ( 531 | D74145D71BE3506300053E40 /* Debug */, 532 | D74145D81BE3506300053E40 /* Release */, 533 | ); 534 | defaultConfigurationIsVisible = 0; 535 | defaultConfigurationName = Release; 536 | }; 537 | D74145D91BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScrollTests" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | D74145DA1BE3506300053E40 /* Debug */, 541 | D74145DB1BE3506300053E40 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | D74145DC1BE3506300053E40 /* Build configuration list for PBXNativeTarget "XTLoopScrollUITests" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | D74145DD1BE3506300053E40 /* Debug */, 550 | D74145DE1BE3506300053E40 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | /* End XCConfigurationList section */ 556 | }; 557 | rootObject = D74145A11BE3506100053E40 /* Project object */; 558 | } 559 | -------------------------------------------------------------------------------- /XTLoopScroll.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /XTLoopScroll.xcodeproj/project.xcworkspace/xcuserdata/tutu.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll.xcodeproj/project.xcworkspace/xcuserdata/tutu.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /XTLoopScroll.xcodeproj/xcuserdata/tutu.xcuserdatad/xcschemes/XTLoopScroll.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /XTLoopScroll.xcodeproj/xcuserdata/tutu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | XTLoopScroll.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D74145A81BE3506100053E40 16 | 17 | primary 18 | 19 | 20 | D74145C11BE3506300053E40 21 | 22 | primary 23 | 24 | 25 | D74145CC1BE3506300053E40 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /XTLoopScroll/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/.DS_Store -------------------------------------------------------------------------------- /XTLoopScroll/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. 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 | -------------------------------------------------------------------------------- /XTLoopScroll/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. 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 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/1.imageset/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/1.imageset/1.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/2.imageset/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/2.imageset/2.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "2.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/3.imageset/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/3.imageset/3.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "3.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/4.imageset/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/4.imageset/4.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "4.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/5.imageset/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/5.imageset/5.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/5.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "5.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-Small@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-Small@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-Spotlight-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-Spotlight-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "29x29", 41 | "idiom" : "ipad", 42 | "filename" : "Icon-Small.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "29x29", 47 | "idiom" : "ipad", 48 | "filename" : "Icon-Small@2x-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "40x40", 53 | "idiom" : "ipad", 54 | "filename" : "Icon-Spotlight-40.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "40x40", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-Spotlight-40@2x-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "76x76", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-76.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "76x76", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-76@2x.png", 73 | "scale" : "2x" 74 | } 75 | ], 76 | "info" : { 77 | "version" : 1, 78 | "author" : "xcode" 79 | } 80 | } -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x-1.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@2x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Akateason/XTLoopScroll/fb0434eda4171cc79a9083680b3f847e8bf6154d/XTLoopScroll/Assets.xcassets/AppIcon.appiconset/Icon-Spotlight-40@3x.png -------------------------------------------------------------------------------- /XTLoopScroll/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /XTLoopScroll/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 | -------------------------------------------------------------------------------- /XTLoopScroll/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 | -------------------------------------------------------------------------------- /XTLoopScroll/HWWeakerTimer/HWWeakTimer.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 ( https://github.com/callmewhy ) 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 | 23 | #import 24 | 25 | typedef void (^HWTimerHandler)(id userInfo); 26 | 27 | @interface HWWeakTimer : NSObject 28 | 29 | + (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval 30 | target:(id)aTarget 31 | selector:(SEL)aSelector 32 | userInfo:(id)userInfo 33 | repeats:(BOOL)repeats; 34 | 35 | + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval 36 | block:(HWTimerHandler)block 37 | userInfo:(id)userInfo 38 | repeats:(BOOL)repeats; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /XTLoopScroll/HWWeakerTimer/HWWeakTimer.m: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2015 ( https://github.com/callmewhy ) 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 | 23 | #import "HWWeakTimer.h" 24 | 25 | @interface HWWeakTimerTarget : NSObject 26 | 27 | @property (nonatomic, weak) id target; 28 | @property (nonatomic, assign) SEL selector; 29 | @property (nonatomic, weak) NSTimer* timer; 30 | 31 | @end 32 | 33 | @implementation HWWeakTimerTarget 34 | 35 | - (void) fire:(NSTimer *)timer { 36 | if(self.target) { 37 | #pragma clang diagnostic push 38 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 39 | [self.target performSelector:self.selector withObject:timer.userInfo afterDelay:0.0f]; 40 | #pragma clang diagnostic pop 41 | } else { 42 | [self.timer invalidate]; 43 | } 44 | } 45 | 46 | @end 47 | 48 | @implementation HWWeakTimer 49 | 50 | + (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval 51 | target:(id)aTarget 52 | selector:(SEL)aSelector 53 | userInfo:(id)userInfo 54 | repeats:(BOOL)repeats { 55 | HWWeakTimerTarget* timerTarget = [[HWWeakTimerTarget alloc] init]; 56 | timerTarget.target = aTarget; 57 | timerTarget.selector = aSelector; 58 | timerTarget.timer = [NSTimer scheduledTimerWithTimeInterval:interval 59 | target:timerTarget 60 | selector:@selector(fire:) 61 | userInfo:userInfo 62 | repeats:repeats]; 63 | return timerTarget.timer; 64 | } 65 | 66 | + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval 67 | block:(HWTimerHandler)block 68 | userInfo:(id)userInfo 69 | repeats:(BOOL)repeats { 70 | NSMutableArray *userInfoArray = [NSMutableArray arrayWithObject:[block copy]]; 71 | if (userInfo != nil) { 72 | [userInfoArray addObject:userInfo]; 73 | } 74 | return [self scheduledTimerWithTimeInterval:interval 75 | target:self 76 | selector:@selector(_timerBlockInvoke:) 77 | userInfo:[userInfoArray copy] 78 | repeats:repeats]; 79 | } 80 | 81 | + (void)_timerBlockInvoke:(NSArray*)userInfo { 82 | HWTimerHandler block = userInfo[0]; 83 | id info = nil; 84 | if (userInfo.count == 2) { 85 | info = userInfo[1]; 86 | } 87 | // or `!block ?: block();` @sunnyxx 88 | if (block) { 89 | block(info); 90 | } 91 | } 92 | 93 | @end -------------------------------------------------------------------------------- /XTLoopScroll/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 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /XTLoopScroll/NSTimer+Addition.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSTimer+Addition.h 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/11/2. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSTimer (Addition) 12 | 13 | - (void)pause ; 14 | 15 | - (void)resume ; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /XTLoopScroll/NSTimer+Addition.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSTimer+Addition.m 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/11/2. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import "NSTimer+Addition.h" 10 | 11 | @implementation NSTimer (Addition) 12 | 13 | - (void)pause 14 | { 15 | [self setFireDate:[NSDate distantFuture]]; 16 | } 17 | 18 | - (void)resume 19 | { 20 | [self setFireDate:[NSDate date]]; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /XTLoopScroll/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /XTLoopScroll/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import "XTLoopScrollView.h" 10 | #import "ViewController.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)tapingCurrentIndex:(NSInteger)currentIndex 19 | { 20 | NSLog(@"currently tapped picture's index is '%ld' ",(long)currentIndex) ; 21 | } 22 | 23 | - (void)viewDidLoad 24 | { 25 | [super viewDidLoad]; 26 | // Do any additional setup after loading the view, typically from a nib. 27 | 28 | self.view.backgroundColor = [UIColor blackColor] ; 29 | 30 | CGRect rect = CGRectMake(0, 20, APPFRAME.size.width, 100) ; 31 | XTLoopScrollView *loopScroll = [[XTLoopScrollView alloc] initWithFrame:rect 32 | andImageList:@[@"1",@"2",@"3",@"4",@"5"] 33 | canLoop:YES 34 | duration:5.0] ; 35 | loopScroll.delegate = self ; 36 | loopScroll.color_pageControl = [UIColor colorWithRed:250.0/255.0 green:219/255.0 blue:249/255.0 alpha:1] ; 37 | loopScroll.color_currentPageControl = [UIColor redColor] ; 38 | 39 | [self.view addSubview:loopScroll] ; 40 | 41 | } 42 | 43 | - (void)didReceiveMemoryWarning { 44 | [super didReceiveMemoryWarning]; 45 | // Dispose of any resources that can be recreated. 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /XTLoopScroll/XTLoopScroll/XTLoopScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XTLoopScrollView.h 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #define APPFRAME [UIScreen mainScreen].bounds 10 | 11 | 12 | #import 13 | 14 | @protocol XTLoopScrollViewDelegate 15 | 16 | - (void)tapingCurrentIndex:(NSInteger)currentIndex ; 17 | 18 | @end 19 | 20 | @interface XTLoopScrollView : UIView 21 | 22 | @property (nonatomic,strong) NSArray *imglist ; //dataSource list , string . 23 | 24 | @property (nonatomic,weak) id delegate ; 25 | @property (nonatomic) UIColor *color_pageControl ; 26 | @property (nonatomic) UIColor *color_currentPageControl ; 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame 29 | canLoop:(BOOL)canLoop 30 | duration:(NSInteger)duration ; 31 | 32 | - (instancetype)initWithFrame:(CGRect)frame 33 | andImageList:(NSArray *)imglist 34 | canLoop:(BOOL)canLoop 35 | duration:(NSInteger)duration ; 36 | 37 | - (void)startLoop ; 38 | - (void)stopLoop ; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /XTLoopScroll/XTLoopScroll/XTLoopScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTLoopScrollView.m 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import "XTLoopScrollView.h" 10 | #import "NSTimer+Addition.h" 11 | #import "HWWeakTimer.h" 12 | 13 | static int IMAGEVIEW_COUNT = 3 ; 14 | 15 | @interface XTLoopScrollView () 16 | { 17 | UIScrollView *_scrollView ; 18 | 19 | UIImageView *_leftImageView; 20 | UIImageView *_centerImageView; 21 | UIImageView *_rightImageView; 22 | 23 | BOOL _bLoop ; 24 | NSInteger _durationOfScroll ; 25 | 26 | NSTimer *_timerLoop ; // 控制循环 27 | NSTimer *_timerOverflow ; // 控制手动后的等待时间 28 | BOOL bOpenTimer ; // 开关 29 | } 30 | @property (nonatomic) int currentImageIndex ; 31 | @property (nonatomic) int imageCount ; 32 | @property (nonatomic,strong) UIPageControl *pageControl ; 33 | 34 | @end 35 | 36 | @implementation XTLoopScrollView 37 | @synthesize color_currentPageControl = _color_currentPageControl , 38 | color_pageControl = _color_pageControl ; 39 | 40 | #pragma mark - Public prop 41 | - (void)setImglist:(NSArray *)imglist 42 | { 43 | _imglist = imglist ; 44 | 45 | self.imageCount = (int)self.imglist.count ; 46 | [self setDefaultImage] ; 47 | } 48 | 49 | - (void)setColor_pageControl:(UIColor *)color_pageControl 50 | { 51 | _color_pageControl = color_pageControl ; 52 | 53 | self.pageControl.pageIndicatorTintColor = _color_pageControl ; 54 | } 55 | 56 | - (UIColor *)color_pageControl 57 | { 58 | if (!_color_pageControl) { 59 | _color_pageControl = [UIColor grayColor] ; 60 | } 61 | return _color_pageControl ; 62 | } 63 | 64 | - (void)setColor_currentPageControl:(UIColor *)color_currentPageControl 65 | { 66 | _color_currentPageControl = color_currentPageControl ; 67 | 68 | self.pageControl.currentPageIndicatorTintColor = _color_currentPageControl ; 69 | } 70 | 71 | - (UIColor *)color_currentPageControl 72 | { 73 | if (!_color_currentPageControl) { 74 | _color_currentPageControl = [UIColor darkGrayColor] ; 75 | } 76 | return _color_currentPageControl ; 77 | } 78 | 79 | #pragma mark - private prop 80 | - (void)setImageCount:(int)imageCount 81 | { 82 | _imageCount = imageCount ; 83 | 84 | if (imageCount <= 1) { 85 | _scrollView.scrollEnabled = NO ; 86 | return ; 87 | } 88 | _scrollView.scrollEnabled = YES ; 89 | self.pageControl.numberOfPages = imageCount ; 90 | CGSize size = [self.pageControl sizeForNumberOfPages:imageCount]; 91 | self.pageControl.bounds = CGRectMake(0, 0, size.width, size.height); 92 | self.pageControl.center = CGPointMake(self.frame.size.width - size.width - 0. , self.frame.size.height - 20.) ; 93 | } 94 | 95 | - (UIPageControl *)pageControl 96 | { 97 | if (!_pageControl) { 98 | _pageControl = [[UIPageControl alloc] init] ; 99 | _pageControl.pageIndicatorTintColor = self.color_pageControl ; 100 | _pageControl.currentPageIndicatorTintColor = self.color_currentPageControl ; 101 | if (!_pageControl.superview) { 102 | [self addSubview:_pageControl]; 103 | } 104 | } 105 | 106 | return _pageControl ; 107 | } 108 | 109 | 110 | #pragma - Initial 111 | - (instancetype)initWithFrame:(CGRect)frame 112 | andImageList:(NSArray *)imglist 113 | canLoop:(BOOL)canLoop 114 | duration:(NSInteger)duration 115 | { 116 | self = [self initWithFrame:frame canLoop:canLoop duration:duration] ; 117 | self.imglist = imglist ; 118 | return self; 119 | } 120 | 121 | - (instancetype)initWithFrame:(CGRect)frame 122 | canLoop:(BOOL)canLoop 123 | duration:(NSInteger)duration 124 | { 125 | self = [super init]; 126 | if (self) 127 | { 128 | self.frame = frame ; 129 | _bLoop = canLoop ; 130 | _durationOfScroll = duration ; 131 | self.backgroundColor = [UIColor whiteColor] ; 132 | [self setup] ; 133 | 134 | if (_bLoop) [self loopStart] ; 135 | } 136 | return self; 137 | } 138 | 139 | 140 | #pragma mark - 141 | 142 | - (void)startLoop 143 | { 144 | [self stopLoop] ; 145 | 146 | if (!_timerLoop.isValid || !_timerLoop) { 147 | [self loopStart] ; 148 | } 149 | } 150 | 151 | - (void)stopLoop 152 | { 153 | _currentImageIndex = 0 ; 154 | [self setViewInDefault] ; 155 | 156 | [_timerLoop invalidate] ; 157 | _timerLoop = nil ; 158 | 159 | if ([_timerOverflow isValid]) [_timerOverflow invalidate] ; 160 | } 161 | 162 | #pragma mark - 163 | 164 | - (void)setup 165 | { 166 | //添加滚动控件 167 | [self addScrollView]; 168 | //添加图片控件 169 | [self addImageViews]; 170 | } 171 | 172 | - (void)loopStart 173 | { 174 | if (_timerLoop == nil) { 175 | _timerLoop = [HWWeakTimer scheduledTimerWithTimeInterval:_durationOfScroll 176 | target:self 177 | selector:@selector(loopAction) 178 | userInfo:nil 179 | repeats:YES] ; 180 | } 181 | 182 | } 183 | 184 | - (void)loopAction 185 | { 186 | if (_imageCount <= 1) return ; 187 | 188 | 189 | int leftImageIndex , rightImageIndex ; 190 | _currentImageIndex = (_currentImageIndex + 1) % _imageCount ; 191 | _centerImageView.image = [UIImage imageNamed:_imglist[_currentImageIndex]] ; 192 | 193 | leftImageIndex = (_currentImageIndex + _imageCount - 1) % _imageCount ; 194 | rightImageIndex = (_currentImageIndex + 1) % _imageCount ; 195 | 196 | _leftImageView.image = [UIImage imageNamed:_imglist[leftImageIndex]] ; 197 | _rightImageView.image = [UIImage imageNamed:_imglist[rightImageIndex]] ; 198 | 199 | [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width , 0) animated:NO] ; 200 | 201 | CATransition *animation = [CATransition animation] ; 202 | [animation setDuration:0.35f] ; 203 | [animation setType:kCATransitionPush] ; 204 | [animation setSubtype:kCATransitionFromRight] ; 205 | [animation setFillMode:kCAFillModeForwards] ; 206 | [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]] ; 207 | [_centerImageView.layer addAnimation:animation forKey:nil] ; 208 | 209 | _pageControl.currentPage=_currentImageIndex ; 210 | 211 | } 212 | 213 | #pragma mark 添加控件 214 | - (void)addScrollView 215 | { 216 | if (!_scrollView) { 217 | _scrollView = [[UIScrollView alloc] init] ; 218 | } 219 | CGRect rect = CGRectZero ; 220 | rect.size = self.frame.size ; 221 | _scrollView.frame = rect ; 222 | _scrollView.bounces = false ; 223 | _scrollView.delegate = self; 224 | _scrollView.contentSize = CGSizeMake(IMAGEVIEW_COUNT * _scrollView.frame.size.width, _scrollView.frame.size.height) ; 225 | //设置当前显示的位置为中间图片 226 | [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0) animated:NO]; 227 | 228 | _scrollView.pagingEnabled = YES; 229 | _scrollView.showsHorizontalScrollIndicator=NO; 230 | 231 | if (![_scrollView superview]) { 232 | [self addSubview:_scrollView] ; 233 | } 234 | 235 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScrollView)] ; 236 | [_scrollView addGestureRecognizer:tapGesture] ; 237 | } 238 | 239 | - (void)tapScrollView 240 | { 241 | NSLog(@"tap in xtloopscroll : %d",_currentImageIndex) ; 242 | [self.delegate tapingCurrentIndex:_currentImageIndex] ; 243 | } 244 | 245 | #pragma mark 添加图片三个控件 246 | - (void)addImageViews 247 | { 248 | _leftImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 249 | _leftImageView.contentMode = UIViewContentModeScaleAspectFill; 250 | _leftImageView.layer.masksToBounds = YES ; 251 | [_scrollView addSubview:_leftImageView]; 252 | _centerImageView = [[UIImageView alloc]initWithFrame:CGRectMake(self.frame.size.width, 0, self.frame.size.width, self.frame.size.height)] ; 253 | _centerImageView.contentMode = UIViewContentModeScaleAspectFill; 254 | _centerImageView.layer.masksToBounds = YES ; 255 | [_scrollView addSubview:_centerImageView] ; 256 | _rightImageView = [[UIImageView alloc]initWithFrame:CGRectMake(2 * self.frame.size.width, 0, self.frame.size.width, self.frame.size.height)] ; 257 | _rightImageView.contentMode = UIViewContentModeScaleAspectFill; 258 | _rightImageView.layer.masksToBounds = YES ; 259 | [_scrollView addSubview:_rightImageView] ; 260 | } 261 | 262 | #pragma mark 设置默认显示图片 263 | - (void)setDefaultImage 264 | { 265 | if (!_imglist || !_imglist.count) { 266 | return ; 267 | } 268 | 269 | _centerImageView.image = [UIImage imageNamed:_imglist[0]] ; 270 | if (_imageCount > 1) 271 | { 272 | _leftImageView.image = [UIImage imageNamed:_imglist[_imageCount - 1]] ; 273 | _rightImageView.image = [UIImage imageNamed:_imglist[1]] ; 274 | } 275 | // current index 276 | _currentImageIndex = 0 ; 277 | _pageControl.currentPage = 0 ; 278 | 279 | } 280 | 281 | #pragma mark 滚动停止事件 282 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 283 | { 284 | //重新加载图片 285 | [self reloadImage]; 286 | //移动到中间 287 | [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0) animated:NO]; 288 | //设置分页 289 | self.pageControl.currentPage = _currentImageIndex; 290 | } 291 | 292 | - (void)setViewInDefault 293 | { 294 | //重新加载图片 295 | [self reloadImage]; 296 | //移动到中间 297 | [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0) animated:NO]; 298 | //设置分页 299 | self.pageControl.currentPage = _currentImageIndex; 300 | } 301 | 302 | 303 | #pragma mark 重新加载图片 304 | - (void)reloadImage 305 | { 306 | if (!_imageCount) { 307 | return ; 308 | } 309 | 310 | [self resumeTimerWithDelay] ; 311 | 312 | int leftImageIndex,rightImageIndex ; 313 | CGPoint offset = [_scrollView contentOffset] ; 314 | 315 | if (offset.x > self.frame.size.width) 316 | { // 向右滑动 317 | _currentImageIndex = (_currentImageIndex + 1) % _imageCount ; 318 | } 319 | else if(offset.x < self.frame.size.width) 320 | { // 向左滑动 321 | _currentImageIndex = (_currentImageIndex + _imageCount - 1) % _imageCount ; 322 | } 323 | 324 | _centerImageView.image = [UIImage imageNamed:_imglist[_currentImageIndex]]; 325 | 326 | // 重新设置左右图片 327 | leftImageIndex = (_currentImageIndex + _imageCount - 1) % _imageCount ; 328 | rightImageIndex = (_currentImageIndex + 1) % _imageCount ; 329 | _leftImageView.image = [UIImage imageNamed:_imglist[leftImageIndex]] ; 330 | _rightImageView.image = [UIImage imageNamed:_imglist[rightImageIndex]] ; 331 | 332 | } 333 | 334 | - (void)resumeTimerWithDelay 335 | { 336 | [_timerLoop pause] ; 337 | 338 | if (!bOpenTimer) 339 | { 340 | if ([_timerOverflow isValid]) 341 | { 342 | [_timerOverflow invalidate] ; 343 | } 344 | 345 | _timerOverflow = [HWWeakTimer scheduledTimerWithTimeInterval:_durationOfScroll 346 | target:self 347 | selector:@selector(timerIsOverflow) 348 | userInfo:nil 349 | repeats:NO] ; 350 | } 351 | } 352 | 353 | - (void)timerIsOverflow 354 | { 355 | bOpenTimer = YES ; 356 | 357 | if (bOpenTimer) 358 | { 359 | [_timerLoop resume] ; 360 | bOpenTimer = NO ; 361 | 362 | [_timerOverflow invalidate] ; 363 | _timerOverflow = nil ; 364 | } 365 | } 366 | 367 | 368 | - (void)dealloc 369 | { 370 | [_timerLoop invalidate] ; 371 | [_timerOverflow invalidate] ; 372 | 373 | _timerLoop = nil ; 374 | _timerOverflow = nil ; 375 | } 376 | 377 | 378 | /* 379 | // Only override drawRect: if you perform custom drawing. 380 | // An empty implementation adversely affects performance during animation. 381 | - (void)drawRect:(CGRect)rect { 382 | // Drawing code 383 | } 384 | */ 385 | 386 | @end 387 | -------------------------------------------------------------------------------- /XTLoopScroll/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // XTLoopScroll 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. 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 | -------------------------------------------------------------------------------- /XTLoopScrollTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /XTLoopScrollTests/XTLoopScrollTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTLoopScrollTests.m 3 | // XTLoopScrollTests 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTLoopScrollTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation XTLoopScrollTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /XTLoopScrollUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /XTLoopScrollUITests/XTLoopScrollUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // XTLoopScrollUITests.m 3 | // XTLoopScrollUITests 4 | // 5 | // Created by TuTu on 15/10/30. 6 | // Copyright © 2015年 teason. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XTLoopScrollUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation XTLoopScrollUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // 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. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | --------------------------------------------------------------------------------