Skip to content

Commit

Permalink
Add InfinitePagingView component.
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Katzian committed Jul 8, 2010
1 parent 2336e72 commit dfccab2
Show file tree
Hide file tree
Showing 14 changed files with 1,315 additions and 0 deletions.
22 changes: 22 additions & 0 deletions InfinitePaging/Classes/InfinitePagingAppDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// InfinitePagingAppDelegate.h
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright Blackwhale GmbH 2010. All rights reserved.
//

#import <UIKit/UIKit.h>

@class InfinitePagingViewController;

@interface InfinitePagingAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
InfinitePagingViewController *viewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet InfinitePagingViewController *viewController;

@end

88 changes: 88 additions & 0 deletions InfinitePaging/Classes/InfinitePagingAppDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//
// InfinitePagingAppDelegate.m
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright Blackwhale GmbH 2010. All rights reserved.
//

#import "InfinitePagingAppDelegate.h"
#import "InfinitePagingViewController.h"

@implementation InfinitePagingAppDelegate

@synthesize window;
@synthesize viewController;


#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Override point for customization after application launch.

// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];

return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}


- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}


#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}


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


@end
38 changes: 38 additions & 0 deletions InfinitePaging/Classes/InfinitePagingView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// InfinitePagingView.h
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright 2010 Blackwhale GmbH. All rights reserved.
//

#import <UIKit/UIKit.h>

@class InfinitePagingView;

// Protocol to define methods for a data souce delegate
@protocol InfinitePagingDataSource

@required
- (UIView*) infinitePagingView:(InfinitePagingView*) infinitePagingView viewForPageIndex:(int) index;

@end


// Interface definition.
@interface InfinitePagingView : UIView <UIScrollViewDelegate> {

id<InfinitePagingDataSource> dataSource; //data source delegate

UIScrollView *scrollView; //internal scroll view
NSMutableDictionary *viewBuffer; //temporary view buffer
int pageIndex; //current page index


}

@property(nonatomic, assign) id<InfinitePagingDataSource> dataSource;

- (id)initWithFrame:(CGRect)frame andDataSource:(id<InfinitePagingDataSource>) ds;

@end
171 changes: 171 additions & 0 deletions InfinitePaging/Classes/InfinitePagingView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//
// InfinitePagingView.m
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright 2010 Blackwhale GmbH. All rights reserved.
//

#import "InfinitePagingView.h"

#define MAX_BUFFER_SIZE 6

// Anonymus category for additional methods and properties
@interface InfinitePagingView()

- (void) setup;
- (void) updateToPage:(int) page;
- (void) setViewForPage:(int) page;
- (void) checkViewBuffer;

@property(nonatomic, retain) UIScrollView *scrollView;
@property(nonatomic, retain) NSMutableDictionary *viewBuffer;

@end




@implementation InfinitePagingView

@synthesize dataSource;
@synthesize scrollView;
@synthesize viewBuffer;


// Do the intial setup of the infinite paging view.
- (void) setup
{
//init page index
pageIndex = -1;

//init view buffer
viewBuffer = [[NSMutableDictionary alloc] init];

//setup view
self.backgroundColor = [UIColor clearColor];

//init scroll view
self.scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
scrollView.backgroundColor = [UIColor clearColor];
scrollView.pagingEnabled = YES;
scrollView.delegate = self;
scrollView.scrollEnabled = YES;

//add scroll view
[self addSubview:scrollView];

//initialize first pages
[self updateToPage:0];
}

// Update to new page. This occurs when the user
// scrolls the view to a new page.
- (void) updateToPage:(int) page
{
if(page != pageIndex)
{
CGFloat pageWidth = scrollView.frame.size.width;
CGSize contentSize = scrollView.frame.size;

contentSize.width = pageWidth * (page + 2);

[self setViewForPage:(page-1)];
[self setViewForPage:page];
[self setViewForPage:(page+1)];

self.scrollView.contentSize = contentSize;
pageIndex = page;
}
}

// Load the view for a given page. Use the dataSource
// to get the view or check the view buffer.
- (void) setViewForPage:(int) page
{
if(page < 0)
return;

//calculate x offset
CGFloat offsetX = scrollView.frame.size.width * page;

//check if view is allready within the view buffer
UIView *view = nil;
if((view = [self.viewBuffer objectForKey:[NSNumber numberWithInt:page]]) == nil)
{
//get view from data source
view = [self.dataSource infinitePagingView:self viewForPageIndex:page];
[self.viewBuffer setObject:view forKey:[NSNumber numberWithInt:page]];

//set the x offset
CGRect viewFrame = view.frame;
viewFrame.origin.x = offsetX;
view.frame = viewFrame;

//add as subview
[self.scrollView addSubview:view];

//check view buffer size
[self checkViewBuffer];
}

}

// Check if view buffer violates the max. view
// buffer size and clean it up if necessary.
- (void) checkViewBuffer
{
if(self.viewBuffer && [self.viewBuffer count] > MAX_BUFFER_SIZE)
{
NSLog(@"checkViewBuffer %d items before cleanup", [self.viewBuffer count]);

for(NSNumber *page in [self.viewBuffer allKeys])
{
if([page intValue] < (pageIndex - 1) || [page intValue] > (pageIndex + 1))
{
UIView *view = [self.viewBuffer objectForKey:page];
[view removeFromSuperview];
[self.viewBuffer removeObjectForKey:page];
}
}

NSLog(@"checkViewBuffer %d items after cleanup", [self.viewBuffer count]);
}
}


#pragma mark -
#pragma mark UIScrollViewDelegate methods

// Notification about any scroll offset change.
- (void)scrollViewDidScroll:(UIScrollView *)sView
{
CGFloat pageWidth = sView.frame.size.width;
int page = floor((sView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
[self updateToPage:page];
}


#pragma mark -
#pragma mark Initialization and memory management

// Initialize the view with given frame and data source.
- (id)initWithFrame:(CGRect)frame andDataSource:(id<InfinitePagingDataSource>) ds
{
if ((self = [super initWithFrame:frame])) {
self.dataSource = ds;
[self setup];
}
return self;
}


- (void)dealloc {
self.scrollView = nil;
self.viewBuffer = nil;

[super dealloc];
}


@end
17 changes: 17 additions & 0 deletions InfinitePaging/Classes/InfinitePagingViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// InfinitePagingViewController.h
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright Blackwhale GmbH 2010. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "InfinitePagingView.h"

@interface InfinitePagingViewController : UIViewController <InfinitePagingDataSource> {

}

@end

54 changes: 54 additions & 0 deletions InfinitePaging/Classes/InfinitePagingViewController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// InfinitePagingViewController.m
// InfinitePaging
//
// Created by Andreas Katzian on 08.07.10.
// Copyright Blackwhale GmbH 2010. All rights reserved.
//

#import "InfinitePagingViewController.h"

@implementation InfinitePagingViewController

- (UIView*) infinitePagingView:(InfinitePagingView*) infinitePagingView viewForPageIndex:(int) index
{
//provide some very simple views with different background
//colors to demonstrate the infinite paging view
UIView *v = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 300)] autorelease];

int r = rand();

if(r%3 == 0)
v.backgroundColor = [UIColor grayColor];
else if(r%5 == 0)
v.backgroundColor = [UIColor greenColor];
else if(r%7 == 0)
v.backgroundColor = [UIColor redColor];
else
v.backgroundColor = [UIColor blueColor];

return v;
}


// Implement viewDidLoad to do additional setup after
// loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];

srand(time(NULL));

InfinitePagingView *infinitePagingView = [[InfinitePagingView alloc]
initWithFrame:CGRectMake(0, 0, 320, 480)
andDataSource:self];

[self.view addSubview:infinitePagingView];
[infinitePagingView release];
}


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

@end
Loading

0 comments on commit dfccab2

Please sign in to comment.