diff --git a/.gitignore b/.gitignore index 5f8982c..2fa7514 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ -*.o -*.mode1v3 +*.xcworkspace *.pbxuser *.perspectivev3 -ATPagingView/ATPagingViewDemo/build -ATArrayView/ATArrayViewDemo/build +*.mode1v3 +xcuserdata +.DS_Store +.svn diff --git a/ATPagingView/ATPagingView.h b/ATPagingView/ATPagingView.h index 13c32b5..984e2cf 100644 --- a/ATPagingView/ATPagingView.h +++ b/ATPagingView/ATPagingView.h @@ -8,13 +8,13 @@ @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 { // subviews UIScrollView *_scrollView; // properties - id _delegate; + id __weak _delegate; CGFloat _gapBetweenPages; NSInteger _pagesToPreload; @@ -31,9 +31,10 @@ BOOL _rotationInProgress; BOOL _scrollViewIsMoving; BOOL _recyclingEnabled; + BOOL _horizontal; } -@property(nonatomic, assign) IBOutlet id delegate; +@property(nonatomic, weak) IBOutlet id delegate; @property(nonatomic, assign) CGFloat gapBetweenPages; // default is 20 @@ -52,6 +53,7 @@ @property(nonatomic, assign, readonly) BOOL moving; @property(nonatomic, assign) BOOL recyclingEnabled; +@property(nonatomic, assign) BOOL horizontal; // default YES - (void)reloadData; // must be called at least once to display something @@ -91,6 +93,6 @@ ATPagingView *_pagingView; } -@property(nonatomic, retain) IBOutlet ATPagingView *pagingView; +@property(nonatomic, strong) IBOutlet ATPagingView *pagingView; @end diff --git a/ATPagingView/ATPagingView.m b/ATPagingView/ATPagingView.m index 38a2eb4..ec8bea7 100644 --- a/ATPagingView/ATPagingView.m +++ b/ATPagingView/ATPagingView.m @@ -39,6 +39,7 @@ @implementation ATPagingView @synthesize moving=_scrollViewIsMoving; @synthesize previousPageIndex=_previousPageIndex; @synthesize recyclingEnabled=_recyclingEnabled; +@synthesize horizontal=_horizontal; #pragma mark - @@ -52,6 +53,7 @@ - (void)commonInit { _pagesToPreload = 1; _recyclingEnabled = YES; _firstLoadedPageIndex = _lastLoadedPageIndex = -1; + _horizontal = YES; // We are using an oversized UIScrollView to implement interpage gaps, // and we need it to clipped on the sides. This is important when @@ -61,7 +63,7 @@ - (void)commonInit { _scrollView = [[UIScrollView alloc] initWithFrame:[self frameForScrollView]]; _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _scrollView.pagingEnabled = YES; - _scrollView.backgroundColor = [UIColor blackColor]; + _scrollView.backgroundColor = [UIColor clearColor]; _scrollView.showsVerticalScrollIndicator = NO; _scrollView.showsHorizontalScrollIndicator = NO; _scrollView.bounces = YES; @@ -84,11 +86,10 @@ - (id)initWithFrame:(CGRect)frame { } - (void)dealloc { - [_scrollView release], _scrollView = nil; + _scrollView = nil; _delegate = nil; - [_recycledPages release], _recycledPages = nil; - [_visiblePages release], _visiblePages = nil; - [super dealloc]; + _recycledPages = nil; + _visiblePages = nil; } @@ -100,10 +101,21 @@ - (void)setGapBetweenPages:(CGFloat)value { } - (void)setPagesToPreload:(NSInteger)value { + BOOL reconfigure = _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 Data @@ -132,8 +144,11 @@ - (UIView *)viewForPageAtIndex:(NSUInteger)index { } - (void)configurePages { - if (_scrollView.frame.size.width <= _gapBetweenPages + 1e-6) + if (_horizontal && (_scrollView.frame.size.width <= _gapBetweenPages + 1e-6)) { + return; // not our time yet + } else if (_scrollView.frame.size.height <= _gapBetweenPages + 1e-6) { return; // not our time yet + } if (_pageCount == 0 && _currentPageIndex > 0) return; // still not our time @@ -144,14 +159,24 @@ - (void)configurePages { // to avoid hiccups while scrolling, do not preload invisible pages temporarily 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)) { #ifdef AT_PAGING_VIEW_TRACE_LAYOUT NSLog(@"configurePages: _scrollView.frame == %@, setting _scrollView.contentSize = %@", NSStringFromCGRect(_scrollView.frame), NSStringFromCGSize(contentSize)); #endif _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 { #ifdef AT_PAGING_VIEW_TRACE_LAYOUT NSLog(@"configurePages: _scrollView.frame == %@", NSStringFromCGRect(_scrollView.frame)); @@ -159,7 +184,12 @@ - (void)configurePages { } 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 NSLog(@"newPageIndex == %d", newPageIndex); #endif @@ -279,7 +309,11 @@ - (void)willAnimateRotation { // // So we set the new size, but keep the old position here. 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 { @@ -287,7 +321,12 @@ - (void)didRotate { // changes, because we move the pages and adjust contentOffset simultaneously. for (UIView *view in _visiblePages) [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; @@ -302,10 +341,21 @@ - (void)setCurrentPageIndex:(NSInteger)newPageIndex { #ifdef AT_PAGING_VIEW_TRACE_LAYOUT NSLog(@"setCurrentPageIndex(%d): _scrollView.frame == %@", newPageIndex, NSStringFromCGRect(_scrollView.frame)); #endif - if (_scrollView.frame.size.width > 0 && fabsf(_scrollView.frame.origin.x - (-_gapBetweenPages/2)) < 1e-6) { - _scrollView.contentOffset = CGPointMake(_scrollView.frame.size.width * newPageIndex, 0); + if (_horizontal && (_scrollView.frame.size.width > 0 && fabsf(_scrollView.frame.origin.x - (-_gapBetweenPages/2)) < 1e-6) ) { + [UIView animateWithDuration:0.3 + animations:^{ + _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) { + [UIView animateWithDuration:0.3 + animations:^{ + _scrollView.contentOffset = CGPointMake(0, _scrollView.frame.size.height * newPageIndex); + }]; } + _currentPageIndex = newPageIndex; + + [self configurePages]; } @@ -324,23 +374,40 @@ - (void)layoutSubviews { _scrollView.frame = newFrame; } - if (oldFrame.size.width != 0 && _scrollView.frame.size.width != oldFrame.size.width) { - // rotation is in progress, don't do any adjustments just yet - } else if (oldFrame.size.height != _scrollView.frame.size.height) { - // some other height change (the initial change from 0 to some specific size, - // or maybe an in-call status bar has appeared or disappeared) - [self configurePages]; + if (_horizontal) { + if (oldFrame.size.width != 0 && _scrollView.frame.size.width != oldFrame.size.width) { + // rotation is in progress, don't do any adjustments just yet + } else if (oldFrame.size.height != _scrollView.frame.size.height) { + // some other height change (the initial change from 0 to some specific size, + // 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 { 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 { 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 { @@ -353,16 +420,24 @@ - (NSInteger)lastLoadedPageIndex { - (CGRect)frameForScrollView { 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 - (CGRect)frameForPageAtIndex:(NSUInteger)index { CGFloat pageWidthWithGap = _scrollView.frame.size.width; + CGFloat pageHeightWithGap = _scrollView.frame.size.height; CGSize pageSize = self.bounds.size; - return CGRectMake(pageWidthWithGap * index + _gapBetweenPages/2, - 0, pageSize.width, pageSize.height); + if (_horizontal) { + return CGRectMake(pageWidthWithGap * index + _gapBetweenPages/2, 0, pageSize.width, pageSize.height); + } else { + return CGRectMake(0, pageHeightWithGap * index + _gapBetweenPages/2, pageSize.width, pageSize.height); + } } @@ -388,7 +463,7 @@ - (void)recyclePage:(UIView *)page { - (UIView *)dequeueReusablePage { UIView *result = [_recycledPages anyObject]; if (result) { - [_recycledPages removeObject:[[result retain] autorelease]]; + [_recycledPages removeObject:result]; } return result; } @@ -455,21 +530,11 @@ @implementation ATPagingViewController @synthesize pagingView=_pagingView; - -#pragma mark - -#pragma mark init/dealloc - -- (void)dealloc { - [_pagingView release], _pagingView = nil; - [super dealloc]; -} - - #pragma mark - #pragma mark View Loading - (void)loadView { - self.view = self.pagingView = [[[ATPagingView alloc] init] autorelease]; + self.view = self.pagingView = [[ATPagingView alloc] init]; } - (void)viewDidLoad { diff --git a/ATPagingView/ATPagingViewDemo/ATPagingViewDemo.xcodeproj/project.pbxproj b/ATPagingView/ATPagingViewDemo/ATPagingViewDemo.xcodeproj/project.pbxproj index b5cc010..93b79c1 100755 --- a/ATPagingView/ATPagingViewDemo/ATPagingViewDemo.xcodeproj/project.pbxproj +++ b/ATPagingView/ATPagingViewDemo/ATPagingViewDemo.xcodeproj/project.pbxproj @@ -197,6 +197,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -211,6 +212,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ATPagingViewDemo_Prefix.pch; diff --git a/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.h b/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.h index cd2ef72..386c1d3 100644 --- a/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.h +++ b/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.h @@ -9,8 +9,8 @@ UINavigationController *navigationController; } -@property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, retain) IBOutlet UINavigationController *navigationController; +@property (nonatomic, strong) IBOutlet UIWindow *window; +@property (nonatomic, strong) IBOutlet UINavigationController *navigationController; @end diff --git a/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.m b/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.m index be0d580..e3a8560 100644 --- a/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.m +++ b/ATPagingView/ATPagingViewDemo/Classes/ATPagingViewDemoAppDelegate.m @@ -49,10 +49,6 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { } -- (void)dealloc { - [window release]; - [super dealloc]; -} @end diff --git a/ATPagingView/ATPagingViewDemo/Classes/DemoPageView.m b/ATPagingView/ATPagingViewDemo/Classes/DemoPageView.m index eb553a8..fd03936 100644 --- a/ATPagingView/ATPagingViewDemo/Classes/DemoPageView.m +++ b/ATPagingView/ATPagingViewDemo/Classes/DemoPageView.m @@ -42,9 +42,6 @@ - (void)drawRect:(CGRect)rect { [[NSString stringWithFormat:@"Page %d", self.tag] drawInRect:textRect withFont:[UIFont boldSystemFontOfSize:17] lineBreakMode:UILineBreakModeClip alignment:UITextAlignmentCenter]; } -- (void)dealloc { - [super dealloc]; -} @end diff --git a/ATPagingView/ATPagingViewDemo/Classes/DemoViewController.m b/ATPagingView/ATPagingViewDemo/Classes/DemoViewController.m index c36534a..59150d8 100644 --- a/ATPagingView/ATPagingViewDemo/Classes/DemoViewController.m +++ b/ATPagingView/ATPagingViewDemo/Classes/DemoViewController.m @@ -14,6 +14,7 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + self.pagingView.horizontal = NO; self.pagingView.currentPageIndex = 3; [self currentPageDidChangeInPagingView:self.pagingView]; } @@ -29,7 +30,7 @@ - (NSInteger)numberOfPagesInPagingView:(ATPagingView *)pagingView { - (UIView *)viewForPageInPagingView:(ATPagingView *)pagingView atIndex:(NSInteger)index { UIView *view = [pagingView dequeueReusablePage]; if (view == nil) { - view = [[[DemoPageView alloc] init] autorelease]; + view = [[DemoPageView alloc] init]; } return view; } diff --git a/ATPagingView/ATPagingViewDemo/main.m b/ATPagingView/ATPagingViewDemo/main.m index bb45d53..a6eabd5 100644 --- a/ATPagingView/ATPagingViewDemo/main.m +++ b/ATPagingView/ATPagingViewDemo/main.m @@ -5,8 +5,8 @@ #import int main(int argc, char *argv[]) { - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; - int retVal = UIApplicationMain(argc, argv, nil, nil); - [pool release]; - return retVal; + @autoreleasepool { + int retVal = UIApplicationMain(argc, argv, nil, nil); + return retVal; + } }