Permalink
Browse files

Added support for vertical paging

  • Loading branch information...
RobPearson67 committed Oct 14, 2011
1 parent 11b2d4a commit 04c5d42dbca87ca547f3864adbd3f8f4e78cf12c
@@ -8,7 +8,7 @@
@protocol ATPagingViewDelegate; @protocol ATPagingViewDelegate;
// a wrapper around UIScrollView in (horizontal) paging mode, with an API similar to UITableView // a wrapper around UIScrollView in paging mode, with an API similar to UITableView
@interface ATPagingView : UIView { @interface ATPagingView : UIView {
// subviews // subviews
UIScrollView *_scrollView; UIScrollView *_scrollView;
@@ -31,6 +31,7 @@
BOOL _rotationInProgress; BOOL _rotationInProgress;
BOOL _scrollViewIsMoving; BOOL _scrollViewIsMoving;
BOOL _recyclingEnabled; BOOL _recyclingEnabled;
BOOL _horizontal;
} }
@property(nonatomic, assign) IBOutlet id<ATPagingViewDelegate> delegate; @property(nonatomic, assign) IBOutlet id<ATPagingViewDelegate> delegate;
@@ -52,6 +53,7 @@
@property(nonatomic, assign, readonly) BOOL moving; @property(nonatomic, assign, readonly) BOOL moving;
@property(nonatomic, assign) BOOL recyclingEnabled; @property(nonatomic, assign) BOOL recyclingEnabled;
@property(nonatomic, assign) BOOL horizontal; // default YES
- (void)reloadData; // must be called at least once to display something - (void)reloadData; // must be called at least once to display something
View
@@ -39,6 +39,7 @@ @implementation ATPagingView
@synthesize moving=_scrollViewIsMoving; @synthesize moving=_scrollViewIsMoving;
@synthesize previousPageIndex=_previousPageIndex; @synthesize previousPageIndex=_previousPageIndex;
@synthesize recyclingEnabled=_recyclingEnabled; @synthesize recyclingEnabled=_recyclingEnabled;
@synthesize horizontal=_horizontal;
#pragma mark - #pragma mark -
@@ -52,6 +53,7 @@ - (void)commonInit {
_pagesToPreload = 1; _pagesToPreload = 1;
_recyclingEnabled = YES; _recyclingEnabled = YES;
_firstLoadedPageIndex = _lastLoadedPageIndex = -1; _firstLoadedPageIndex = _lastLoadedPageIndex = -1;
_horizontal = YES;
// We are using an oversized UIScrollView to implement interpage gaps, // We are using an oversized UIScrollView to implement interpage gaps,
// and we need it to clipped on the sides. This is important when // and we need it to clipped on the sides. This is important when
@@ -100,10 +102,21 @@ - (void)setGapBetweenPages:(CGFloat)value {
} }
- (void)setPagesToPreload:(NSInteger)value { - (void)setPagesToPreload:(NSInteger)value {
BOOL reconfigure = _pagesToPreload != value;
_pagesToPreload = value; _pagesToPreload = value;
[self configurePages]; if (reconfigure) {
[self configurePages];
}
} }
-(void)setHorizontal:(BOOL)value {
BOOL reconfigure = _horizontal != value;
_horizontal = value;
if (reconfigure) {
[self layoutIfNeeded]; // force call to layoutSubview to set _scrollView.frame
[self configurePages];
}
}
#pragma mark - #pragma mark -
#pragma mark Data #pragma mark Data
@@ -132,8 +145,11 @@ - (UIView *)viewForPageAtIndex:(NSUInteger)index {
} }
- (void)configurePages { - (void)configurePages {
if (_scrollView.frame.size.width <= _gapBetweenPages + 1e-6) if (_horizontal && (_scrollView.frame.size.width <= _gapBetweenPages + 1e-6)) {
return; // not our time yet return; // not our time yet
} else if (_scrollView.frame.size.height <= _gapBetweenPages + 1e-6) {
return; // not our time yet
}
if (_pageCount == 0 && _currentPageIndex > 0) if (_pageCount == 0 && _currentPageIndex > 0)
return; // still not our time return; // still not our time
@@ -144,22 +160,37 @@ - (void)configurePages {
// to avoid hiccups while scrolling, do not preload invisible pages temporarily // to avoid hiccups while scrolling, do not preload invisible pages temporarily
BOOL quickMode = (_scrollViewIsMoving && _pagesToPreload > 0); BOOL quickMode = (_scrollViewIsMoving && _pagesToPreload > 0);
CGSize contentSize = CGSizeMake(_scrollView.frame.size.width * _pageCount, _scrollView.frame.size.height); CGSize contentSize;
if (_horizontal) {
contentSize = CGSizeMake(_scrollView.frame.size.width * _pageCount, _scrollView.frame.size.height);
} else {
contentSize = CGSizeMake(_scrollView.frame.size.width, _scrollView.frame.size.height * _pageCount);
}
if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) { if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
#ifdef AT_PAGING_VIEW_TRACE_LAYOUT #ifdef AT_PAGING_VIEW_TRACE_LAYOUT
NSLog(@"configurePages: _scrollView.frame == %@, setting _scrollView.contentSize = %@", NSLog(@"configurePages: _scrollView.frame == %@, setting _scrollView.contentSize = %@",
NSStringFromCGRect(_scrollView.frame), NSStringFromCGSize(contentSize)); NSStringFromCGRect(_scrollView.frame), NSStringFromCGSize(contentSize));
#endif #endif
_scrollView.contentSize = contentSize; _scrollView.contentSize = contentSize;
_scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * _currentPageIndex, 0); if (_horizontal) {
_scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * _currentPageIndex, 0);
} else {
_scrollView.contentOffset = CGPointMake(0, _scrollView.frame.size.height * _currentPageIndex);
}
} else { } else {
#ifdef AT_PAGING_VIEW_TRACE_LAYOUT #ifdef AT_PAGING_VIEW_TRACE_LAYOUT
NSLog(@"configurePages: _scrollView.frame == %@", NSStringFromCGRect(_scrollView.frame)); NSLog(@"configurePages: _scrollView.frame == %@", NSStringFromCGRect(_scrollView.frame));
#endif #endif
} }
CGRect visibleBounds = _scrollView.bounds; CGRect visibleBounds = _scrollView.bounds;
NSInteger newPageIndex = MIN(MAX(floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0), _pageCount - 1); NSInteger newPageIndex;
if (_horizontal) {
newPageIndex = MIN(MAX(floorf(CGRectGetMidX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0), _pageCount - 1);
} else {
newPageIndex = MIN(MAX(floorf(CGRectGetMidY(visibleBounds) / CGRectGetHeight(visibleBounds)), 0), _pageCount - 1);
}
#ifdef AT_PAGING_VIEW_TRACE_LAYOUT #ifdef AT_PAGING_VIEW_TRACE_LAYOUT
NSLog(@"newPageIndex == %d", newPageIndex); NSLog(@"newPageIndex == %d", newPageIndex);
#endif #endif
@@ -279,15 +310,24 @@ - (void)willAnimateRotation {
// //
// So we set the new size, but keep the old position here. // So we set the new size, but keep the old position here.
CGSize pageSize = _scrollView.frame.size; CGSize pageSize = _scrollView.frame.size;
[self viewForPageAtIndex:_currentPageIndex].frame = CGRectMake(_scrollView.contentOffset.x + _gapBetweenPages/2, 0, pageSize.width - _gapBetweenPages, pageSize.height); if (_horizontal) {
[self viewForPageAtIndex:_currentPageIndex].frame = CGRectMake(_scrollView.contentOffset.x + _gapBetweenPages/2, 0, pageSize.width - _gapBetweenPages, pageSize.height);
} else {
[self viewForPageAtIndex:_currentPageIndex].frame = CGRectMake(0, _scrollView.contentOffset.y + _gapBetweenPages/2, pageSize.width, pageSize.height - _gapBetweenPages);
}
} }
- (void)didRotate { - (void)didRotate {
// Adjust frames according to the new page size - this does not cause any visible // Adjust frames according to the new page size - this does not cause any visible
// changes, because we move the pages and adjust contentOffset simultaneously. // changes, because we move the pages and adjust contentOffset simultaneously.
for (UIView *view in _visiblePages) for (UIView *view in _visiblePages)
[self configurePage:view forIndex:view.tag]; [self configurePage:view forIndex:view.tag];
_scrollView.contentOffset = CGPointMake(_currentPageIndex * _scrollView.frame.size.width, 0);
if (_horizontal) {
_scrollView.contentOffset = CGPointMake(_currentPageIndex * _scrollView.frame.size.width, 0);
} else {
_scrollView.contentOffset = CGPointMake(0, _currentPageIndex * _scrollView.frame.size.height);
}
_rotationInProgress = NO; _rotationInProgress = NO;
@@ -302,8 +342,10 @@ - (void)setCurrentPageIndex:(NSInteger)newPageIndex {
#ifdef AT_PAGING_VIEW_TRACE_LAYOUT #ifdef AT_PAGING_VIEW_TRACE_LAYOUT
NSLog(@"setCurrentPageIndex(%d): _scrollView.frame == %@", newPageIndex, NSStringFromCGRect(_scrollView.frame)); NSLog(@"setCurrentPageIndex(%d): _scrollView.frame == %@", newPageIndex, NSStringFromCGRect(_scrollView.frame));
#endif #endif
if (_scrollView.frame.size.width > 0 && fabsf(_scrollView.frame.origin.x - (-_gapBetweenPages/2)) < 1e-6) { if (_horizontal && (_scrollView.frame.size.width > 0 && fabsf(_scrollView.frame.origin.x - (-_gapBetweenPages/2)) < 1e-6) ) {
_scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * newPageIndex, 0); _scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * newPageIndex, 0);
} else if (_scrollView.frame.size.height > 0 && fabsf(_scrollView.frame.origin.y - (-_gapBetweenPages/2)) < 1e-6) {
_scrollView.contentOffset = CGPointMake(0, _scrollView.frame.size.height * newPageIndex);
} }
_currentPageIndex = newPageIndex; _currentPageIndex = newPageIndex;
} }
@@ -324,23 +366,40 @@ - (void)layoutSubviews {
_scrollView.frame = newFrame; _scrollView.frame = newFrame;
} }
if (oldFrame.size.width != 0 && _scrollView.frame.size.width != oldFrame.size.width) { if (_horizontal) {
// rotation is in progress, don't do any adjustments just yet if (oldFrame.size.width != 0 && _scrollView.frame.size.width != oldFrame.size.width) {
} else if (oldFrame.size.height != _scrollView.frame.size.height) { // rotation is in progress, don't do any adjustments just yet
// some other height change (the initial change from 0 to some specific size, } else if (oldFrame.size.height != _scrollView.frame.size.height) {
// or maybe an in-call status bar has appeared or disappeared) // some other height change (the initial change from 0 to some specific size,
[self configurePages]; // or maybe an in-call status bar has appeared or disappeared)
[self configurePages];
}
} else {
if (oldFrame.size.height != 0 && _scrollView.frame.size.height != oldFrame.size.height) {
// rotation is in progress, don't do any adjustments just yet
} else if (oldFrame.size.width != _scrollView.frame.size.width) {
// some other width change ?
[self configurePages];
}
} }
} }
- (NSInteger)firstVisiblePageIndex { - (NSInteger)firstVisiblePageIndex {
CGRect visibleBounds = _scrollView.bounds; CGRect visibleBounds = _scrollView.bounds;
return MAX(floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0); if (_horizontal) {
return MAX(floorf(CGRectGetMinX(visibleBounds) / CGRectGetWidth(visibleBounds)), 0);
} else {
return MAX(floorf(CGRectGetMinY(visibleBounds) / CGRectGetHeight(visibleBounds)), 0);
}
} }
- (NSInteger)lastVisiblePageIndex { - (NSInteger)lastVisiblePageIndex {
CGRect visibleBounds = _scrollView.bounds; CGRect visibleBounds = _scrollView.bounds;
return MIN(floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds)), _pageCount - 1); if (_horizontal) {
return MIN(floorf((CGRectGetMaxX(visibleBounds)-1) / CGRectGetWidth(visibleBounds)), _pageCount - 1);
} else {
return MIN(floorf((CGRectGetMaxY(visibleBounds)-1) / CGRectGetHeight(visibleBounds)), _pageCount - 1);
}
} }
- (NSInteger)firstLoadedPageIndex { - (NSInteger)firstLoadedPageIndex {
@@ -353,16 +412,24 @@ - (NSInteger)lastLoadedPageIndex {
- (CGRect)frameForScrollView { - (CGRect)frameForScrollView {
CGSize size = self.bounds.size; CGSize size = self.bounds.size;
return CGRectMake(-_gapBetweenPages/2, 0, size.width + _gapBetweenPages, size.height); if (_horizontal) {
return CGRectMake(-_gapBetweenPages/2, 0, size.width + _gapBetweenPages, size.height);
} else {
return CGRectMake(0, -_gapBetweenPages/2, size.width, size.height + _gapBetweenPages);
}
} }
// not public because this is in scroll view coordinates // not public because this is in scroll view coordinates
- (CGRect)frameForPageAtIndex:(NSUInteger)index { - (CGRect)frameForPageAtIndex:(NSUInteger)index {
CGFloat pageWidthWithGap = _scrollView.frame.size.width; CGFloat pageWidthWithGap = _scrollView.frame.size.width;
CGFloat pageHeightWithGap = _scrollView.frame.size.height;
CGSize pageSize = self.bounds.size; CGSize pageSize = self.bounds.size;
return CGRectMake(pageWidthWithGap * index + _gapBetweenPages/2, if (_horizontal) {
0, pageSize.width, pageSize.height); return CGRectMake(pageWidthWithGap * index + _gapBetweenPages/2, 0, pageSize.width, pageSize.height);
} else {
return CGRectMake(0, pageHeightWithGap * index + _gapBetweenPages/2, pageSize.width, pageSize.height);
}
} }
@@ -14,6 +14,7 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
self.pagingView.horizontal = NO;
self.pagingView.currentPageIndex = 3; self.pagingView.currentPageIndex = 3;
[self currentPageDidChangeInPagingView:self.pagingView]; [self currentPageDidChangeInPagingView:self.pagingView];
} }

0 comments on commit 04c5d42

Please sign in to comment.