Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.o
*.mode1v3
*.xcworkspace
*.pbxuser
*.perspectivev3
ATPagingView/ATPagingViewDemo/build
ATArrayView/ATArrayViewDemo/build
*.mode1v3
xcuserdata
.DS_Store
.svn
10 changes: 6 additions & 4 deletions ATPagingView/ATPagingView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ATPagingViewDelegate> _delegate;
id<ATPagingViewDelegate> __weak _delegate;
CGFloat _gapBetweenPages;
NSInteger _pagesToPreload;

Expand All @@ -31,9 +31,10 @@
BOOL _rotationInProgress;
BOOL _scrollViewIsMoving;
BOOL _recyclingEnabled;
BOOL _horizontal;
}

@property(nonatomic, assign) IBOutlet id<ATPagingViewDelegate> delegate;
@property(nonatomic, weak) IBOutlet id<ATPagingViewDelegate> delegate;

@property(nonatomic, assign) CGFloat gapBetweenPages; // default is 20

Expand All @@ -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

Expand Down Expand Up @@ -91,6 +93,6 @@
ATPagingView *_pagingView;
}

@property(nonatomic, retain) IBOutlet ATPagingView *pagingView;
@property(nonatomic, strong) IBOutlet ATPagingView *pagingView;

@end
139 changes: 102 additions & 37 deletions ATPagingView/ATPagingView.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ @implementation ATPagingView
@synthesize moving=_scrollViewIsMoving;
@synthesize previousPageIndex=_previousPageIndex;
@synthesize recyclingEnabled=_recyclingEnabled;
@synthesize horizontal=_horizontal;


#pragma mark -
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
}


Expand All @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -144,22 +159,37 @@ - (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));
#endif
}

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
Expand Down Expand Up @@ -279,15 +309,24 @@ - (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 {
// Adjust frames according to the new page size - this does not cause any visible
// 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;

Expand All @@ -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];
}


Expand All @@ -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 {
Expand All @@ -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);
}
}


Expand All @@ -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;
}
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}


- (void)dealloc {
[window release];
[super dealloc];
}


@end
3 changes: 0 additions & 3 deletions ATPagingView/ATPagingViewDemo/Classes/DemoPageView.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion ATPagingView/ATPagingViewDemo/Classes/DemoViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
Expand All @@ -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;
}
Expand Down
Loading