├── .gitignore ├── GMCPagingScrollView.podspec ├── GMCPagingScrollView ├── GMCPagingScrollView.h └── GMCPagingScrollView.m ├── GMCPagingScrollViewDemo ├── GMCPagingScrollView │ └── Info.plist ├── GMCPagingScrollViewDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── GMCPagingScrollViewDemo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── DemoViewController.h │ ├── DemoViewController.m │ ├── GMCPagingScrollViewDemo-Info.plist │ ├── GMCPagingScrollViewDemo-Prefix.pch │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata 3 | *.xccheckout 4 | -------------------------------------------------------------------------------- /GMCPagingScrollView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "GMCPagingScrollView" 3 | s.version = "1.0.3" 4 | s.summary = "Horizontally scrolling, paging UIScrollView that supports page preloading, page dequeuing, and infinite scrolling." 5 | s.author = 'Hilton Campbell' 6 | s.homepage = "https://github.com/GalacticMegacorp/GMCPagingScrollView" 7 | s.license = 'MIT' 8 | 9 | s.description = <<-DESC 10 | GMCPagingScrollView is a UIView containing a horizontally scrolling, paging 11 | UIScrollView that supports page preloading, page dequeueing, and infinite scrolling. 12 | DESC 13 | 14 | s.source = { :git => "https://github.com/GalacticMegacorp/GMCPagingScrollView.git", :tag => s.version.to_s } 15 | 16 | s.platform = :ios, '5.1' 17 | s.source_files = 'GMCPagingScrollView' 18 | s.requires_arc = true 19 | end 20 | -------------------------------------------------------------------------------- /GMCPagingScrollView/GMCPagingScrollView.h: -------------------------------------------------------------------------------- 1 | // GMCPagingScrollView.h 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | @import UIKit; 24 | 25 | //! Project version number for GMCPagingScrollView. 26 | FOUNDATION_EXPORT double GMCPagingScrollViewVersionNumber; 27 | 28 | //! Project version string for GMCPagingScrollView. 29 | FOUNDATION_EXPORT const unsigned char GMCPagingScrollViewVersionString[]; 30 | 31 | @protocol GMCPagingScrollViewDelegate; 32 | @protocol GMCPagingScrollViewDataSource; 33 | 34 | @interface GMCPagingScrollView : UIView 35 | 36 | @property (nonatomic, weak) id delegate; 37 | @property (nonatomic, weak) id dataSource; 38 | @property (nonatomic, assign) CGFloat interpageSpacing; 39 | @property (nonatomic, assign) UIEdgeInsets pageInsets; 40 | @property (nonatomic, assign) NSUInteger numberOfPreloadedPagesOnEachSide; 41 | @property (nonatomic, assign) BOOL infiniteScroll; 42 | @property (nonatomic, assign) NSUInteger currentPageIndex; 43 | @property (nonatomic, strong, readonly) UIScrollView *scrollView; 44 | 45 | - (void)registerClass:(Class)class forReuseIdentifier:(NSString *)reuseIdentifier; 46 | 47 | - (id)dequeueReusablePageWithIdentifier:(NSString *)reuseIdentifier; 48 | 49 | - (id)pageAtIndex:(NSUInteger)page; 50 | 51 | - (NSUInteger)indexOfPage:(id)page; 52 | 53 | - (NSArray *)visiblePages; 54 | 55 | - (void)setCurrentPageIndex:(NSUInteger)index animated:(BOOL)animated; 56 | 57 | - (void)setCurrentPageIndex:(NSInteger)index reloadData:(BOOL)reloadData; 58 | 59 | - (void)reloadData; 60 | 61 | /** 62 | * This implementation assumes pages will only be inserted after the current index. It will need to be enhanced to support other use cases. 63 | */ 64 | - (void)insertPagesAtIndexes:(NSIndexSet *)indexes; 65 | 66 | - (BOOL)isDragging; 67 | 68 | @end 69 | 70 | 71 | 72 | @protocol GMCPagingScrollViewDelegate 73 | 74 | @optional 75 | 76 | - (void)pagingScrollView:(GMCPagingScrollView *)pagingScrollView didScrollToPageAtIndex:(NSUInteger)index; 77 | 78 | - (void)pagingScrollViewWillBeginDragging:(GMCPagingScrollView *)pagingScrollView; 79 | 80 | - (void)pagingScrollViewDidScroll:(GMCPagingScrollView *)pagingScrollView; 81 | 82 | - (void)pagingScrollViewDidFinishScrolling:(GMCPagingScrollView *)pagingScrollView; 83 | 84 | - (void)pagingScrollView:(GMCPagingScrollView *)pagingScrollView layoutPageAtIndex:(NSUInteger)index; 85 | 86 | - (void)pagingScrollView:(GMCPagingScrollView *)pagingScrollView didEndDisplayingPage:(UIView *)page atIndex:(NSUInteger)index; 87 | 88 | @end 89 | 90 | 91 | 92 | @protocol GMCPagingScrollViewDataSource 93 | 94 | - (NSUInteger)numberOfPagesInPagingScrollView:(GMCPagingScrollView *)pagingScrollView; 95 | 96 | - (UIView *)pagingScrollView:(GMCPagingScrollView *)pagingScrollView pageForIndex:(NSUInteger)index; 97 | 98 | @end -------------------------------------------------------------------------------- /GMCPagingScrollView/GMCPagingScrollView.m: -------------------------------------------------------------------------------- 1 | // GMCPagingScrollView.m 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "GMCPagingScrollView.h" 24 | #import 25 | 26 | static const CGFloat kDefaultInterpageSpacing = 40; 27 | 28 | 29 | 30 | typedef void(^GMCPagingInternalScrollViewLayoutSubviewsBlock)(); 31 | 32 | @interface GMCPagingInternalScrollView : UIScrollView 33 | 34 | @property (nonatomic, copy) GMCPagingInternalScrollViewLayoutSubviewsBlock layoutSubviewsBlock; 35 | 36 | @end 37 | 38 | @implementation GMCPagingInternalScrollView 39 | 40 | - (void)layoutSubviews { 41 | [super layoutSubviews]; 42 | 43 | if (self.layoutSubviewsBlock) { 44 | self.layoutSubviewsBlock(); 45 | } 46 | } 47 | 48 | @end 49 | 50 | 51 | 52 | @interface UIView (GMCPagingScrollView) 53 | 54 | @property (nonatomic, copy) NSString *pagingScrollViewReuseIdentifier; 55 | @property (nonatomic, assign) NSUInteger pagingScrollViewPageIndex; 56 | 57 | @end 58 | 59 | @implementation UIView (GMCPagingScrollView) 60 | 61 | static char pagingScrollViewReuseIdentifierKey; 62 | static char pagingScrollViewPageIndexKey; 63 | 64 | - (void)setPagingScrollViewReuseIdentifier:(NSString *)pagingScrollViewReuseIdentifier { 65 | objc_setAssociatedObject(self, &pagingScrollViewReuseIdentifierKey, pagingScrollViewReuseIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC); 66 | } 67 | 68 | - (NSString *)pagingScrollViewReuseIdentifier { 69 | return objc_getAssociatedObject(self, &pagingScrollViewReuseIdentifierKey); 70 | } 71 | 72 | - (void)setPagingScrollViewPageIndex:(NSUInteger)pagingScrollViewPageIndex { 73 | objc_setAssociatedObject(self, &pagingScrollViewPageIndexKey, @(pagingScrollViewPageIndex), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 74 | } 75 | 76 | - (NSUInteger)pagingScrollViewPageIndex { 77 | return [objc_getAssociatedObject(self, &pagingScrollViewPageIndexKey) unsignedIntegerValue]; 78 | } 79 | 80 | @end 81 | 82 | 83 | 84 | @interface GMCPagingScrollView () 85 | 86 | @property (nonatomic, strong, readwrite) UIScrollView *scrollView; 87 | @property (nonatomic, strong) NSMutableSet *visiblePageSet; 88 | 89 | @property (nonatomic, strong) NSMutableDictionary *classByReuseIdentifier; 90 | @property (nonatomic, strong) NSMutableDictionary *reusablePageSetByReuseIdentifier; 91 | 92 | @property (nonatomic, assign) BOOL inLayoutSubviews; 93 | 94 | @end 95 | 96 | @implementation GMCPagingScrollView 97 | 98 | - (id)initWithFrame:(CGRect)frame { 99 | if ((self = [super initWithFrame:frame])) { 100 | [self initialize]; 101 | } 102 | return self; 103 | } 104 | 105 | - (id)initWithCoder:(NSCoder *)aDecoder { 106 | if ((self = [super initWithCoder:aDecoder])) { 107 | [self initialize]; 108 | } 109 | return self; 110 | } 111 | 112 | - (void)initialize { 113 | self.interpageSpacing = kDefaultInterpageSpacing; 114 | self.clipsToBounds = YES; 115 | 116 | self.scrollView = [[GMCPagingInternalScrollView alloc] initWithFrame:[self frameForScrollView]]; 117 | self.scrollView.scrollsToTop = NO; 118 | self.scrollView.pagingEnabled = YES; 119 | self.scrollView.showsVerticalScrollIndicator = NO; 120 | self.scrollView.showsHorizontalScrollIndicator = NO; 121 | self.scrollView.delegate = self; 122 | self.scrollView.clipsToBounds = NO; 123 | [self addSubview:self.scrollView]; 124 | 125 | __weak GMCPagingScrollView *weakSelf = self; 126 | ((GMCPagingInternalScrollView *)self.scrollView).layoutSubviewsBlock = ^() { 127 | [weakSelf performInfiniteScrollJumpIfNecessary]; 128 | }; 129 | 130 | self.visiblePageSet = [[NSMutableSet alloc] init]; 131 | 132 | self.classByReuseIdentifier = [NSMutableDictionary dictionary]; 133 | self.reusablePageSetByReuseIdentifier = [NSMutableDictionary dictionary]; 134 | } 135 | 136 | - (void)setInterpageSpacing:(CGFloat)interpageSpacing { 137 | _interpageSpacing = interpageSpacing; 138 | [self setNeedsLayout]; 139 | } 140 | 141 | - (CGRect)frameForScrollView { 142 | CGRect frame = self.bounds; 143 | frame.origin.x += self.pageInsets.left - self.interpageSpacing / 2; 144 | frame.size.width += self.interpageSpacing - self.pageInsets.left - self.pageInsets.right; 145 | return frame; 146 | } 147 | 148 | - (CGRect)frameForPageAtActualIndex:(NSUInteger)index { 149 | CGRect pageFrame = UIEdgeInsetsInsetRect(self.bounds, self.pageInsets); 150 | pageFrame.origin.x = ([self frameForScrollView].size.width * index) + self.interpageSpacing / 2; 151 | return pageFrame; 152 | } 153 | 154 | - (void)layoutSubviews { 155 | self.inLayoutSubviews = YES; 156 | 157 | [super layoutSubviews]; 158 | 159 | CGRect frameForScrollView = [self frameForScrollView]; 160 | if (!CGRectEqualToRect(self.scrollView.frame, frameForScrollView)) { 161 | NSUInteger currentPageIndex = self.currentPageIndex; 162 | 163 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 164 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 165 | 166 | self.scrollView.frame = frameForScrollView; 167 | self.scrollView.contentSize = CGSizeMake(frameForScrollView.size.width * numberOfActualPages, frameForScrollView.size.height); 168 | self.scrollView.contentOffset = CGPointMake(frameForScrollView.size.width * currentPageIndex, 0); 169 | 170 | for (UIView *page in self.visiblePageSet) { 171 | NSUInteger index = [self indexOfPage:page]; 172 | page.frame = [self frameForPageAtActualIndex:index]; 173 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:layoutPageAtIndex:)]) { 174 | [self.delegate pagingScrollView:self layoutPageAtIndex:index]; 175 | } 176 | } 177 | } 178 | 179 | self.inLayoutSubviews = NO; 180 | } 181 | 182 | - (void)performInfiniteScrollJumpIfNecessary { 183 | if (self.infiniteScroll) { 184 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 185 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 186 | 187 | NSUInteger currentPageIndex = roundf(self.scrollView.contentOffset.x / self.scrollView.bounds.size.width); 188 | if (currentPageIndex < [self numberOfInfiniteScrollPages] / 2) { 189 | // Perform an "infinite scroll" jump 190 | NSInteger pageIndex = [self.dataSource numberOfPagesInPagingScrollView:self] + currentPageIndex % [self.dataSource numberOfPagesInPagingScrollView:self]; 191 | NSInteger pageDifference = pageIndex - currentPageIndex; 192 | self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x + pageDifference * self.scrollView.bounds.size.width, self.scrollView.contentOffset.y); 193 | } else if (currentPageIndex > numberOfActualPages - 1 - [self numberOfInfiniteScrollPages] / 2) { 194 | // Perform an "infinite scroll" jump 195 | NSInteger pageIndex = currentPageIndex % [self.dataSource numberOfPagesInPagingScrollView:self]; 196 | NSInteger pageDifference = currentPageIndex - pageIndex; 197 | self.scrollView.contentOffset = CGPointMake(self.scrollView.contentOffset.x - pageDifference * self.scrollView.bounds.size.width, self.scrollView.contentOffset.y); 198 | } 199 | } 200 | } 201 | 202 | - (NSUInteger)numberOfInfiniteScrollPages { 203 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 204 | return (self.infiniteScroll && numberOfPages > 0 ? 2 : 0); 205 | } 206 | 207 | - (void)registerClass:(Class)class forReuseIdentifier:(NSString *)reuseIdentifier { 208 | self.classByReuseIdentifier[reuseIdentifier] = class; 209 | } 210 | 211 | - (id)dequeueReusablePageWithIdentifier:(NSString *)reuseIdentifier { 212 | NSMutableSet *reusablePageSet = [self reusablePageSetForReuseIdentifier:reuseIdentifier]; 213 | 214 | UIView *page = [reusablePageSet anyObject]; 215 | if (page) { 216 | [reusablePageSet removeObject:page]; 217 | } else { 218 | Class class = self.classByReuseIdentifier[reuseIdentifier]; 219 | page = [[class alloc] initWithFrame:self.bounds]; 220 | page.pagingScrollViewReuseIdentifier = reuseIdentifier; 221 | } 222 | return page; 223 | } 224 | 225 | - (NSMutableSet *)reusablePageSetForReuseIdentifier:(NSString *)reuseIdentifier { 226 | NSMutableSet *reusablePageSet = self.reusablePageSetByReuseIdentifier[reuseIdentifier]; 227 | if (!reusablePageSet) { 228 | reusablePageSet = [NSMutableSet set]; 229 | self.reusablePageSetByReuseIdentifier[reuseIdentifier] = reusablePageSet; 230 | } 231 | return reusablePageSet; 232 | } 233 | 234 | - (UIView *)pageAtIndex:(NSUInteger)index { 235 | for (UIView *page in self.visiblePageSet) { 236 | if ([self indexOfPage:page] == index) { 237 | return page; 238 | } 239 | } 240 | return nil; 241 | } 242 | 243 | - (NSUInteger)indexOfPage:(UIView *)page { 244 | NSUInteger pageIndex = page.pagingScrollViewPageIndex; 245 | return pageIndex; 246 | } 247 | 248 | - (NSArray *)visiblePages { 249 | return [self.visiblePageSet allObjects]; 250 | } 251 | 252 | - (BOOL)isDisplayingPageForIndex:(NSUInteger)index { 253 | BOOL foundPage = NO; 254 | for (UIView *page in self.visiblePageSet) { 255 | if ([self indexOfPage:page] == index) { 256 | foundPage = YES; 257 | break; 258 | } 259 | } 260 | return foundPage; 261 | } 262 | 263 | - (void)tilePages { 264 | // Calculate which pages are visible 265 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 266 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 267 | 268 | NSInteger firstNeededActualPageIndex = MAX(floorf(CGRectGetMinX(self.scrollView.bounds) / CGRectGetWidth(self.scrollView.bounds)) - self.numberOfPreloadedPagesOnEachSide, 0); 269 | NSInteger lastNeededActualPageIndex = MIN(floorf((CGRectGetMaxX(self.scrollView.bounds) - 1) / CGRectGetWidth(self.scrollView.bounds)) + self.numberOfPreloadedPagesOnEachSide, numberOfActualPages - 1); 270 | 271 | if (self.infiniteScroll && numberOfPages > 0) { 272 | // Move visible pages that are in the wrong place due to an "infinite scroll" jump 273 | for (NSInteger actualPageIndex = firstNeededActualPageIndex; actualPageIndex <= lastNeededActualPageIndex; actualPageIndex++) { 274 | NSInteger index = actualPageIndex % numberOfPages; 275 | 276 | UIView *page = [self pageAtIndex:index]; 277 | if (page) { 278 | page.frame = [self frameForPageAtActualIndex:actualPageIndex]; 279 | } 280 | } 281 | } 282 | 283 | // Recycle no-longer-visible pages 284 | NSMutableSet *neededPageIndexes = [NSMutableSet set]; 285 | if (numberOfPages > 0) { 286 | for (NSInteger actualPageIndex = firstNeededActualPageIndex; actualPageIndex <= lastNeededActualPageIndex; actualPageIndex++) { 287 | [neededPageIndexes addObject:@(actualPageIndex % numberOfPages)]; 288 | } 289 | } 290 | 291 | NSMutableSet *reusablePages = [NSMutableSet set]; 292 | for (UIView *page in self.visiblePageSet) { 293 | if (numberOfPages == 0 || ![neededPageIndexes containsObject:@([self indexOfPage:page])]) { 294 | NSString *reuseIdentifier = page.pagingScrollViewReuseIdentifier; 295 | if (reuseIdentifier) { 296 | NSMutableSet *reusablePageSet = [self reusablePageSetForReuseIdentifier:reuseIdentifier]; 297 | [reusablePageSet addObject:page]; 298 | } 299 | 300 | [reusablePages addObject:page]; 301 | [page removeFromSuperview]; 302 | 303 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:didEndDisplayingPage:atIndex:)]) { 304 | [self.delegate pagingScrollView:self didEndDisplayingPage:page atIndex:[self indexOfPage:page]]; 305 | } 306 | } 307 | } 308 | [self.visiblePageSet minusSet:reusablePages]; 309 | 310 | // Add missing pages 311 | if (numberOfPages > 0) { 312 | for (NSInteger actualPageIndex = firstNeededActualPageIndex; actualPageIndex <= lastNeededActualPageIndex; actualPageIndex++) { 313 | NSInteger index = actualPageIndex % numberOfPages; 314 | 315 | if (![self isDisplayingPageForIndex:index]) { 316 | UIView *page = [self.dataSource pagingScrollView:self pageForIndex:index]; 317 | [self.scrollView addSubview:page]; 318 | [self.visiblePageSet addObject:page]; 319 | page.pagingScrollViewPageIndex = index; 320 | page.frame = [self frameForPageAtActualIndex:actualPageIndex]; 321 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:layoutPageAtIndex:)]) { 322 | [self.delegate pagingScrollView:self layoutPageAtIndex:index]; 323 | } 324 | } 325 | } 326 | } 327 | } 328 | 329 | - (void)reloadDataWithCurrentPageIndex:(NSInteger)currentPageIndex { 330 | for (UIView *page in self.visiblePageSet) { 331 | [page removeFromSuperview]; 332 | 333 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:didEndDisplayingPage:atIndex:)]) { 334 | [self.delegate pagingScrollView:self didEndDisplayingPage:page atIndex:page.pagingScrollViewPageIndex]; 335 | } 336 | } 337 | [self.visiblePageSet removeAllObjects]; 338 | [self.reusablePageSetByReuseIdentifier removeAllObjects]; 339 | 340 | CGRect frameForScrollView = [self frameForScrollView]; 341 | self.inLayoutSubviews = YES; 342 | self.scrollView.contentSize = CGSizeMake(frameForScrollView.size.width * [self.dataSource numberOfPagesInPagingScrollView:self], 343 | frameForScrollView.size.height); 344 | self.inLayoutSubviews = NO; 345 | 346 | // Unset the delegate temporarily so that the current page index can be updated without triggering any page loading 347 | id previousDelegate = self.scrollView.delegate; 348 | self.scrollView.delegate = nil; 349 | [self setCurrentPageIndex:currentPageIndex animated:NO]; 350 | _currentPageIndex = currentPageIndex; 351 | self.scrollView.delegate = previousDelegate; 352 | 353 | [self tilePages]; 354 | } 355 | 356 | - (void)reloadData { 357 | for (UIView *page in self.visiblePageSet) { 358 | [page removeFromSuperview]; 359 | 360 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:didEndDisplayingPage:atIndex:)]) { 361 | [self.delegate pagingScrollView:self didEndDisplayingPage:page atIndex:[self indexOfPage:page]]; 362 | } 363 | } 364 | [self.visiblePageSet removeAllObjects]; 365 | [self.reusablePageSetByReuseIdentifier removeAllObjects]; 366 | 367 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 368 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 369 | 370 | CGRect frameForScrollView = [self frameForScrollView]; 371 | self.scrollView.contentSize = CGSizeMake(frameForScrollView.size.width * numberOfActualPages, frameForScrollView.size.height); 372 | 373 | [self tilePages]; 374 | } 375 | 376 | - (void)insertPagesAtIndexes:(NSIndexSet *)indexes { 377 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 378 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 379 | 380 | CGRect frameForScrollView = [self frameForScrollView]; 381 | self.scrollView.contentSize = CGSizeMake(frameForScrollView.size.width * numberOfActualPages, frameForScrollView.size.height); 382 | } 383 | 384 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 385 | UIView *view = [super hitTest:point withEvent:event]; 386 | if (view == self) { 387 | return self.scrollView; 388 | } 389 | return view; 390 | } 391 | 392 | - (BOOL)isDragging { 393 | return self.scrollView.dragging; 394 | } 395 | 396 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { 397 | if ([self.delegate respondsToSelector:@selector(pagingScrollViewWillBeginDragging:)]) { 398 | [self.delegate pagingScrollViewWillBeginDragging:self]; 399 | } 400 | } 401 | 402 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 403 | if (!self.inLayoutSubviews) { 404 | if ([self.delegate respondsToSelector:@selector(pagingScrollViewDidScroll:)]) { 405 | [self.delegate pagingScrollViewDidScroll:self]; 406 | } 407 | 408 | NSUInteger numberOfPages = [self.dataSource numberOfPagesInPagingScrollView:self]; 409 | NSUInteger numberOfActualPages = numberOfPages + [self numberOfInfiniteScrollPages]; 410 | 411 | NSUInteger currentPageIndex = (numberOfPages > 0 ? MAX(MIN((NSInteger)roundf(self.scrollView.contentOffset.x / self.scrollView.bounds.size.width), 412 | (NSInteger)numberOfActualPages - 1), 0) % numberOfPages : 0); 413 | if (self.currentPageIndex != currentPageIndex) { 414 | _currentPageIndex = currentPageIndex; 415 | if ([self.delegate respondsToSelector:@selector(pagingScrollView:didScrollToPageAtIndex:)]) { 416 | [self.delegate pagingScrollView:self didScrollToPageAtIndex:self.currentPageIndex]; 417 | } 418 | } 419 | 420 | [self tilePages]; 421 | } 422 | } 423 | 424 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 425 | if ([self.delegate respondsToSelector:@selector(pagingScrollViewDidFinishScrolling:)]) { 426 | [self.delegate pagingScrollViewDidFinishScrolling:self]; 427 | } 428 | } 429 | 430 | - (void)setCurrentPageIndex:(NSUInteger)index animated:(BOOL)animated { 431 | [self.scrollView setContentOffset:CGPointMake(index * self.scrollView.bounds.size.width, 0) animated:animated]; 432 | } 433 | 434 | - (void)setCurrentPageIndex:(NSUInteger)index { 435 | [self setCurrentPageIndex:index animated:NO]; 436 | } 437 | 438 | - (void)setCurrentPageIndex:(NSInteger)currentPageIndex reloadData:(BOOL)reloadData { 439 | if (reloadData) { 440 | [self reloadDataWithCurrentPageIndex:currentPageIndex]; 441 | } else { 442 | [self setCurrentPageIndex:currentPageIndex animated:NO]; 443 | } 444 | } 445 | 446 | - (CGPoint)contentOffset { 447 | return self.scrollView.contentOffset; 448 | } 449 | 450 | - (void)setContentOffset:(CGPoint)contentOffset { 451 | self.scrollView.contentOffset = contentOffset; 452 | } 453 | 454 | @end 455 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollView/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BD061FC51BD55D8B0026A635 /* GMCPagingScrollView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD061FBE1BD55D8B0026A635 /* GMCPagingScrollView.framework */; }; 11 | BD061FC61BD55D8B0026A635 /* GMCPagingScrollView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BD061FBE1BD55D8B0026A635 /* GMCPagingScrollView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | BD061FCA1BD55D990026A635 /* GMCPagingScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = D97F78FC1802D82800DF237C /* GMCPagingScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | BD061FCB1BD55D9C0026A635 /* GMCPagingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D97F78FD1802D82800DF237C /* GMCPagingScrollView.m */; }; 14 | D97F78CC1802D70800DF237C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D97F78CB1802D70800DF237C /* Foundation.framework */; }; 15 | D97F78CE1802D70800DF237C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D97F78CD1802D70800DF237C /* CoreGraphics.framework */; }; 16 | D97F78D01802D70800DF237C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D97F78CF1802D70800DF237C /* UIKit.framework */; }; 17 | D97F78D61802D70800DF237C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D97F78D41802D70800DF237C /* InfoPlist.strings */; }; 18 | D97F78D81802D70800DF237C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D97F78D71802D70800DF237C /* main.m */; }; 19 | D97F78DC1802D70800DF237C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D97F78DB1802D70800DF237C /* AppDelegate.m */; }; 20 | D97F78FE1802D82800DF237C /* GMCPagingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = D97F78FD1802D82800DF237C /* GMCPagingScrollView.m */; }; 21 | D97F79011802D8BE00DF237C /* DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D97F79001802D8BE00DF237C /* DemoViewController.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | BD061FC31BD55D8B0026A635 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = D97F78C01802D70800DF237C /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = BD061FBD1BD55D8B0026A635; 30 | remoteInfo = GMCPagingScrollView; 31 | }; 32 | /* End PBXContainerItemProxy section */ 33 | 34 | /* Begin PBXCopyFilesBuildPhase section */ 35 | BDABF6C81BD55B9B00482D77 /* Embed Frameworks */ = { 36 | isa = PBXCopyFilesBuildPhase; 37 | buildActionMask = 2147483647; 38 | dstPath = ""; 39 | dstSubfolderSpec = 10; 40 | files = ( 41 | BD061FC61BD55D8B0026A635 /* GMCPagingScrollView.framework in Embed Frameworks */, 42 | ); 43 | name = "Embed Frameworks"; 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXCopyFilesBuildPhase section */ 47 | 48 | /* Begin PBXFileReference section */ 49 | BD061FBE1BD55D8B0026A635 /* GMCPagingScrollView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GMCPagingScrollView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | BD061FC21BD55D8B0026A635 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | D97F78C81802D70800DF237C /* GMCPagingScrollViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GMCPagingScrollViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | D97F78CB1802D70800DF237C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 53 | D97F78CD1802D70800DF237C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 54 | D97F78CF1802D70800DF237C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 55 | D97F78D31802D70800DF237C /* GMCPagingScrollViewDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GMCPagingScrollViewDemo-Info.plist"; sourceTree = ""; }; 56 | D97F78D51802D70800DF237C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 57 | D97F78D71802D70800DF237C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 58 | D97F78D91802D70800DF237C /* GMCPagingScrollViewDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GMCPagingScrollViewDemo-Prefix.pch"; sourceTree = ""; }; 59 | D97F78DA1802D70800DF237C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 60 | D97F78DB1802D70800DF237C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 61 | D97F78FC1802D82800DF237C /* GMCPagingScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GMCPagingScrollView.h; sourceTree = ""; }; 62 | D97F78FD1802D82800DF237C /* GMCPagingScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GMCPagingScrollView.m; sourceTree = ""; }; 63 | D97F78FF1802D8BE00DF237C /* DemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoViewController.h; sourceTree = ""; }; 64 | D97F79001802D8BE00DF237C /* DemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoViewController.m; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | BD061FBA1BD55D8B0026A635 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | D97F78C51802D70800DF237C /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | BD061FC51BD55D8B0026A635 /* GMCPagingScrollView.framework in Frameworks */, 80 | D97F78CE1802D70800DF237C /* CoreGraphics.framework in Frameworks */, 81 | D97F78D01802D70800DF237C /* UIKit.framework in Frameworks */, 82 | D97F78CC1802D70800DF237C /* Foundation.framework in Frameworks */, 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | /* End PBXFrameworksBuildPhase section */ 87 | 88 | /* Begin PBXGroup section */ 89 | BD061FBF1BD55D8B0026A635 /* GMCPagingScrollView */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | BD061FC21BD55D8B0026A635 /* Info.plist */, 93 | ); 94 | path = GMCPagingScrollView; 95 | sourceTree = ""; 96 | }; 97 | D97F78BF1802D70800DF237C = { 98 | isa = PBXGroup; 99 | children = ( 100 | D97F78D11802D70800DF237C /* GMCPagingScrollViewDemo */, 101 | D97F78FA1802D7EB00DF237C /* Vendor */, 102 | BD061FBF1BD55D8B0026A635 /* GMCPagingScrollView */, 103 | D97F78CA1802D70800DF237C /* Frameworks */, 104 | D97F78C91802D70800DF237C /* Products */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | D97F78C91802D70800DF237C /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | D97F78C81802D70800DF237C /* GMCPagingScrollViewDemo.app */, 112 | BD061FBE1BD55D8B0026A635 /* GMCPagingScrollView.framework */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | D97F78CA1802D70800DF237C /* Frameworks */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | D97F78CB1802D70800DF237C /* Foundation.framework */, 121 | D97F78CD1802D70800DF237C /* CoreGraphics.framework */, 122 | D97F78CF1802D70800DF237C /* UIKit.framework */, 123 | ); 124 | name = Frameworks; 125 | sourceTree = ""; 126 | }; 127 | D97F78D11802D70800DF237C /* GMCPagingScrollViewDemo */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | D97F78DA1802D70800DF237C /* AppDelegate.h */, 131 | D97F78DB1802D70800DF237C /* AppDelegate.m */, 132 | D97F78FF1802D8BE00DF237C /* DemoViewController.h */, 133 | D97F79001802D8BE00DF237C /* DemoViewController.m */, 134 | D97F78D21802D70800DF237C /* Supporting Files */, 135 | ); 136 | path = GMCPagingScrollViewDemo; 137 | sourceTree = ""; 138 | }; 139 | D97F78D21802D70800DF237C /* Supporting Files */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | D97F78D31802D70800DF237C /* GMCPagingScrollViewDemo-Info.plist */, 143 | D97F78D41802D70800DF237C /* InfoPlist.strings */, 144 | D97F78D71802D70800DF237C /* main.m */, 145 | D97F78D91802D70800DF237C /* GMCPagingScrollViewDemo-Prefix.pch */, 146 | ); 147 | name = "Supporting Files"; 148 | sourceTree = ""; 149 | }; 150 | D97F78FA1802D7EB00DF237C /* Vendor */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | D97F78FB1802D82800DF237C /* GMCPagingScrollView */, 154 | ); 155 | name = Vendor; 156 | sourceTree = ""; 157 | }; 158 | D97F78FB1802D82800DF237C /* GMCPagingScrollView */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | D97F78FC1802D82800DF237C /* GMCPagingScrollView.h */, 162 | D97F78FD1802D82800DF237C /* GMCPagingScrollView.m */, 163 | ); 164 | name = GMCPagingScrollView; 165 | path = ../GMCPagingScrollView; 166 | sourceTree = ""; 167 | }; 168 | /* End PBXGroup section */ 169 | 170 | /* Begin PBXHeadersBuildPhase section */ 171 | BD061FBB1BD55D8B0026A635 /* Headers */ = { 172 | isa = PBXHeadersBuildPhase; 173 | buildActionMask = 2147483647; 174 | files = ( 175 | BD061FCA1BD55D990026A635 /* GMCPagingScrollView.h in Headers */, 176 | ); 177 | runOnlyForDeploymentPostprocessing = 0; 178 | }; 179 | /* End PBXHeadersBuildPhase section */ 180 | 181 | /* Begin PBXNativeTarget section */ 182 | BD061FBD1BD55D8B0026A635 /* GMCPagingScrollView */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = BD061FC71BD55D8B0026A635 /* Build configuration list for PBXNativeTarget "GMCPagingScrollView" */; 185 | buildPhases = ( 186 | BD061FB91BD55D8B0026A635 /* Sources */, 187 | BD061FBA1BD55D8B0026A635 /* Frameworks */, 188 | BD061FBB1BD55D8B0026A635 /* Headers */, 189 | BD061FBC1BD55D8B0026A635 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | ); 195 | name = GMCPagingScrollView; 196 | productName = GMCPagingScrollView; 197 | productReference = BD061FBE1BD55D8B0026A635 /* GMCPagingScrollView.framework */; 198 | productType = "com.apple.product-type.framework"; 199 | }; 200 | D97F78C71802D70800DF237C /* GMCPagingScrollViewDemo */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = D97F78F41802D70800DF237C /* Build configuration list for PBXNativeTarget "GMCPagingScrollViewDemo" */; 203 | buildPhases = ( 204 | D97F78C41802D70800DF237C /* Sources */, 205 | D97F78C51802D70800DF237C /* Frameworks */, 206 | D97F78C61802D70800DF237C /* Resources */, 207 | BDABF6C81BD55B9B00482D77 /* Embed Frameworks */, 208 | ); 209 | buildRules = ( 210 | ); 211 | dependencies = ( 212 | BD061FC41BD55D8B0026A635 /* PBXTargetDependency */, 213 | ); 214 | name = GMCPagingScrollViewDemo; 215 | productName = GMCPagingScrollViewDemo; 216 | productReference = D97F78C81802D70800DF237C /* GMCPagingScrollViewDemo.app */; 217 | productType = "com.apple.product-type.application"; 218 | }; 219 | /* End PBXNativeTarget section */ 220 | 221 | /* Begin PBXProject section */ 222 | D97F78C01802D70800DF237C /* Project object */ = { 223 | isa = PBXProject; 224 | attributes = { 225 | LastUpgradeCheck = 0500; 226 | ORGANIZATIONNAME = "Galactic Megacorp"; 227 | TargetAttributes = { 228 | BD061FBD1BD55D8B0026A635 = { 229 | CreatedOnToolsVersion = 7.1; 230 | }; 231 | }; 232 | }; 233 | buildConfigurationList = D97F78C31802D70800DF237C /* Build configuration list for PBXProject "GMCPagingScrollViewDemo" */; 234 | compatibilityVersion = "Xcode 3.2"; 235 | developmentRegion = English; 236 | hasScannedForEncodings = 0; 237 | knownRegions = ( 238 | en, 239 | ); 240 | mainGroup = D97F78BF1802D70800DF237C; 241 | productRefGroup = D97F78C91802D70800DF237C /* Products */; 242 | projectDirPath = ""; 243 | projectRoot = ""; 244 | targets = ( 245 | D97F78C71802D70800DF237C /* GMCPagingScrollViewDemo */, 246 | BD061FBD1BD55D8B0026A635 /* GMCPagingScrollView */, 247 | ); 248 | }; 249 | /* End PBXProject section */ 250 | 251 | /* Begin PBXResourcesBuildPhase section */ 252 | BD061FBC1BD55D8B0026A635 /* Resources */ = { 253 | isa = PBXResourcesBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | ); 257 | runOnlyForDeploymentPostprocessing = 0; 258 | }; 259 | D97F78C61802D70800DF237C /* Resources */ = { 260 | isa = PBXResourcesBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | D97F78D61802D70800DF237C /* InfoPlist.strings in Resources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXResourcesBuildPhase section */ 268 | 269 | /* Begin PBXSourcesBuildPhase section */ 270 | BD061FB91BD55D8B0026A635 /* Sources */ = { 271 | isa = PBXSourcesBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | BD061FCB1BD55D9C0026A635 /* GMCPagingScrollView.m in Sources */, 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | D97F78C41802D70800DF237C /* Sources */ = { 279 | isa = PBXSourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | D97F78DC1802D70800DF237C /* AppDelegate.m in Sources */, 283 | D97F78FE1802D82800DF237C /* GMCPagingScrollView.m in Sources */, 284 | D97F78D81802D70800DF237C /* main.m in Sources */, 285 | D97F79011802D8BE00DF237C /* DemoViewController.m in Sources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | /* End PBXSourcesBuildPhase section */ 290 | 291 | /* Begin PBXTargetDependency section */ 292 | BD061FC41BD55D8B0026A635 /* PBXTargetDependency */ = { 293 | isa = PBXTargetDependency; 294 | target = BD061FBD1BD55D8B0026A635 /* GMCPagingScrollView */; 295 | targetProxy = BD061FC31BD55D8B0026A635 /* PBXContainerItemProxy */; 296 | }; 297 | /* End PBXTargetDependency section */ 298 | 299 | /* Begin PBXVariantGroup section */ 300 | D97F78D41802D70800DF237C /* InfoPlist.strings */ = { 301 | isa = PBXVariantGroup; 302 | children = ( 303 | D97F78D51802D70800DF237C /* en */, 304 | ); 305 | name = InfoPlist.strings; 306 | sourceTree = ""; 307 | }; 308 | /* End PBXVariantGroup section */ 309 | 310 | /* Begin XCBuildConfiguration section */ 311 | BD061FC81BD55D8B0026A635 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | APPLICATION_EXTENSION_API_ONLY = YES; 315 | CLANG_WARN_UNREACHABLE_CODE = YES; 316 | CURRENT_PROJECT_VERSION = 1; 317 | DEBUG_INFORMATION_FORMAT = dwarf; 318 | DEFINES_MODULE = YES; 319 | DYLIB_COMPATIBILITY_VERSION = 1; 320 | DYLIB_CURRENT_VERSION = 1; 321 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 322 | ENABLE_STRICT_OBJC_MSGSEND = YES; 323 | ENABLE_TESTABILITY = YES; 324 | GCC_NO_COMMON_BLOCKS = YES; 325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 326 | INFOPLIST_FILE = GMCPagingScrollView/Info.plist; 327 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 328 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 329 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 330 | MTL_ENABLE_DEBUG_INFO = YES; 331 | PRODUCT_BUNDLE_IDENTIFIER = com.galacticmegacorp.GMCPagingScrollView; 332 | PRODUCT_NAME = "$(TARGET_NAME)"; 333 | SKIP_INSTALL = YES; 334 | VERSIONING_SYSTEM = "apple-generic"; 335 | VERSION_INFO_PREFIX = ""; 336 | }; 337 | name = Debug; 338 | }; 339 | BD061FC91BD55D8B0026A635 /* Release */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | APPLICATION_EXTENSION_API_ONLY = YES; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | COPY_PHASE_STRIP = NO; 345 | CURRENT_PROJECT_VERSION = 1; 346 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 347 | DEFINES_MODULE = YES; 348 | DYLIB_COMPATIBILITY_VERSION = 1; 349 | DYLIB_CURRENT_VERSION = 1; 350 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 351 | ENABLE_STRICT_OBJC_MSGSEND = YES; 352 | GCC_NO_COMMON_BLOCKS = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | INFOPLIST_FILE = GMCPagingScrollView/Info.plist; 355 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 356 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 357 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 358 | MTL_ENABLE_DEBUG_INFO = NO; 359 | PRODUCT_BUNDLE_IDENTIFIER = com.galacticmegacorp.GMCPagingScrollView; 360 | PRODUCT_NAME = "$(TARGET_NAME)"; 361 | SKIP_INSTALL = YES; 362 | VERSIONING_SYSTEM = "apple-generic"; 363 | VERSION_INFO_PREFIX = ""; 364 | }; 365 | name = Release; 366 | }; 367 | D97F78F21802D70800DF237C /* Debug */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | ALWAYS_SEARCH_USER_PATHS = NO; 371 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_MODULES = YES; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_EMPTY_BODY = YES; 380 | CLANG_WARN_ENUM_CONVERSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | COPY_PHASE_STRIP = NO; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_OPTIMIZATION_LEVEL = 0; 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; 398 | GCC_WARN_UNUSED_FUNCTION = YES; 399 | GCC_WARN_UNUSED_VARIABLE = YES; 400 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 401 | ONLY_ACTIVE_ARCH = YES; 402 | SDKROOT = iphoneos; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | }; 405 | name = Debug; 406 | }; 407 | D97F78F31802D70800DF237C /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ALWAYS_SEARCH_USER_PATHS = NO; 411 | ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; 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__DUPLICATE_METHOD_MATCH = YES; 424 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 425 | COPY_PHASE_STRIP = YES; 426 | ENABLE_NS_ASSERTIONS = NO; 427 | GCC_C_LANGUAGE_STANDARD = gnu99; 428 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 429 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 430 | GCC_WARN_UNDECLARED_SELECTOR = YES; 431 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 432 | GCC_WARN_UNUSED_FUNCTION = YES; 433 | GCC_WARN_UNUSED_VARIABLE = YES; 434 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 435 | SDKROOT = iphoneos; 436 | TARGETED_DEVICE_FAMILY = "1,2"; 437 | VALIDATE_PRODUCT = YES; 438 | }; 439 | name = Release; 440 | }; 441 | D97F78F51802D70800DF237C /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 445 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 446 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 447 | GCC_PREFIX_HEADER = "GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Prefix.pch"; 448 | INFOPLIST_FILE = "GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Info.plist"; 449 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 450 | PRODUCT_NAME = "$(TARGET_NAME)"; 451 | WRAPPER_EXTENSION = app; 452 | }; 453 | name = Debug; 454 | }; 455 | D97F78F61802D70800DF237C /* Release */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 459 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 460 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 461 | GCC_PREFIX_HEADER = "GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Prefix.pch"; 462 | INFOPLIST_FILE = "GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Info.plist"; 463 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 464 | PRODUCT_NAME = "$(TARGET_NAME)"; 465 | WRAPPER_EXTENSION = app; 466 | }; 467 | name = Release; 468 | }; 469 | /* End XCBuildConfiguration section */ 470 | 471 | /* Begin XCConfigurationList section */ 472 | BD061FC71BD55D8B0026A635 /* Build configuration list for PBXNativeTarget "GMCPagingScrollView" */ = { 473 | isa = XCConfigurationList; 474 | buildConfigurations = ( 475 | BD061FC81BD55D8B0026A635 /* Debug */, 476 | BD061FC91BD55D8B0026A635 /* Release */, 477 | ); 478 | defaultConfigurationIsVisible = 0; 479 | defaultConfigurationName = Release; 480 | }; 481 | D97F78C31802D70800DF237C /* Build configuration list for PBXProject "GMCPagingScrollViewDemo" */ = { 482 | isa = XCConfigurationList; 483 | buildConfigurations = ( 484 | D97F78F21802D70800DF237C /* Debug */, 485 | D97F78F31802D70800DF237C /* Release */, 486 | ); 487 | defaultConfigurationIsVisible = 0; 488 | defaultConfigurationName = Release; 489 | }; 490 | D97F78F41802D70800DF237C /* Build configuration list for PBXNativeTarget "GMCPagingScrollViewDemo" */ = { 491 | isa = XCConfigurationList; 492 | buildConfigurations = ( 493 | D97F78F51802D70800DF237C /* Debug */, 494 | D97F78F61802D70800DF237C /* Release */, 495 | ); 496 | defaultConfigurationIsVisible = 0; 497 | defaultConfigurationName = Release; 498 | }; 499 | /* End XCConfigurationList section */ 500 | }; 501 | rootObject = D97F78C01802D70800DF237C /* Project object */; 502 | } 503 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // AppDelegate.h 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | @interface AppDelegate : UIResponder 24 | 25 | @property (strong, nonatomic) UIWindow *window; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // AppDelegate.m 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "AppDelegate.h" 24 | #import "DemoViewController.h" 25 | 26 | @implementation AppDelegate 27 | 28 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 29 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 30 | self.window.backgroundColor = [UIColor whiteColor]; 31 | 32 | DemoViewController *viewController = [[DemoViewController alloc] init]; 33 | self.window.rootViewController = viewController; 34 | 35 | [self.window makeKeyAndVisible]; 36 | 37 | return YES; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/DemoViewController.h: -------------------------------------------------------------------------------- 1 | // DemoViewController.h 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | @interface DemoViewController : UIViewController 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/DemoViewController.m: -------------------------------------------------------------------------------- 1 | // DemoViewController.m 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "DemoViewController.h" 24 | #import "GMCPagingScrollView.h" 25 | 26 | static NSString * const kPageIdentifier = @"Page"; 27 | 28 | @interface DemoViewController () 29 | 30 | @property (nonatomic, strong) GMCPagingScrollView *pagingScrollView; 31 | 32 | @end 33 | 34 | @implementation DemoViewController 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | 39 | self.pagingScrollView = [[GMCPagingScrollView alloc] initWithFrame:self.view.bounds]; 40 | self.pagingScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 41 | self.pagingScrollView.dataSource = self; 42 | self.pagingScrollView.infiniteScroll = YES; 43 | self.pagingScrollView.interpageSpacing = 0; 44 | [self.view addSubview:self.pagingScrollView]; 45 | 46 | [self.pagingScrollView registerClass:[UIView class] forReuseIdentifier:kPageIdentifier]; 47 | 48 | [self.pagingScrollView reloadData]; 49 | } 50 | 51 | #pragma mark - GMCPagingScrollViewDataSource 52 | 53 | - (NSUInteger)numberOfPagesInPagingScrollView:(GMCPagingScrollView *)pagingScrollView { 54 | return 3; 55 | } 56 | 57 | - (UIView *)pagingScrollView:(GMCPagingScrollView *)pagingScrollView pageForIndex:(NSUInteger)index { 58 | UIView *page = [pagingScrollView dequeueReusablePageWithIdentifier:kPageIdentifier]; 59 | 60 | switch (index) { 61 | case 0: 62 | page.backgroundColor = [UIColor redColor]; 63 | break; 64 | case 1: 65 | page.backgroundColor = [UIColor greenColor]; 66 | break; 67 | case 2: 68 | page.backgroundColor = [UIColor blueColor]; 69 | break; 70 | } 71 | 72 | return page; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.galacticmegacorp.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 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 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/GMCPagingScrollViewDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /GMCPagingScrollViewDemo/GMCPagingScrollViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // main.m 2 | // 3 | // Copyright (c) 2013 Hilton Campbell 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "AppDelegate.h" 24 | 25 | int main(int argc, char * argv[]) { 26 | @autoreleasepool { 27 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Hilton Campbell 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GMCPagingScrollView [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 2 | 3 | GMCPagingScrollView is a UIView containing a horizontally scrolling paging UIScrollView that supports page preloading, page dequeueing, and infinite scrolling. 4 | 5 | ## License 6 | 7 | GMCPagingScrollView is available under the MIT license. See the LICENSE file for more info. 8 | --------------------------------------------------------------------------------