├── .gitignore ├── LICENSE ├── Leaves ├── LeavesCache.h ├── LeavesCache.m ├── LeavesView.h ├── LeavesView.m ├── LeavesViewController.h └── LeavesViewController.m ├── LeavesExamples.xcodeproj └── project.pbxproj ├── LeavesExamples ├── Classes │ ├── ExamplesViewController.h │ ├── ExamplesViewController.m │ ├── ImageExampleViewController.h │ ├── ImageExampleViewController.m │ ├── LeavesAppDelegate.h │ ├── LeavesAppDelegate.m │ ├── PDFExampleViewController.h │ ├── PDFExampleViewController.m │ ├── ProceduralExampleViewController.h │ └── ProceduralExampleViewController.m ├── LeavesExamples_Prefix.pch ├── Other │ ├── Utilities.h │ └── Utilities.m ├── Resources │ ├── Default-568h@2x.png │ ├── LeavesExamples-Info.plist │ ├── MainWindow-iPad.xib │ ├── MainWindow.xib │ ├── kitten.jpg │ ├── kitten2.jpg │ ├── kitten3.jpg │ └── paper.pdf └── main.m └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 Tom Brow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice, and every other copyright notice found in this software, and all the attributions in every file, and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Leaves/LeavesCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesCache.h 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 5/12/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol LeavesViewDataSource; 12 | 13 | @interface LeavesCache : NSObject 14 | 15 | @property (nonatomic, assign) CGSize pageSize; 16 | @property (assign) id dataSource; 17 | 18 | - (id)initWithPageSize:(CGSize)aPageSize; 19 | - (CGImageRef)cachedImageForPageIndex:(NSUInteger)pageIndex; 20 | - (void)precacheImageForPageIndex:(NSUInteger)pageIndex; 21 | - (void)minimizeToPageIndex:(NSUInteger)pageIndex; 22 | - (void)flush; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Leaves/LeavesCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesCache.m 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 5/12/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "LeavesCache.h" 10 | #import "LeavesView.h" 11 | 12 | @interface LeavesCache () 13 | 14 | @property (readonly) NSMutableDictionary *pageCache; 15 | 16 | @end 17 | 18 | @implementation LeavesCache 19 | 20 | - (id)initWithPageSize:(CGSize)aPageSize 21 | { 22 | if (self = [super init]) { 23 | _pageSize = aPageSize; 24 | _pageCache = [[NSMutableDictionary alloc] init]; 25 | } 26 | return self; 27 | } 28 | 29 | - (void)dealloc 30 | { 31 | [_pageCache release]; 32 | [super dealloc]; 33 | } 34 | 35 | - (CGImageRef)imageForPageIndex:(NSUInteger)pageIndex { 36 | if (CGSizeEqualToSize(self.pageSize, CGSizeZero)) 37 | return NULL; 38 | 39 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 40 | CGContextRef context = CGBitmapContextCreate(NULL, 41 | self.pageSize.width, 42 | self.pageSize.height, 43 | 8, /* bits per component*/ 44 | self.pageSize.width * 4, /* bytes per row */ 45 | colorSpace, 46 | kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 47 | CGColorSpaceRelease(colorSpace); 48 | CGContextClipToRect(context, CGRectMake(0, 0, self.pageSize.width, self.pageSize.height)); 49 | 50 | [self.dataSource renderPageAtIndex:pageIndex inContext:context]; 51 | 52 | CGImageRef image = CGBitmapContextCreateImage(context); 53 | CGContextRelease(context); 54 | 55 | [UIImage imageWithCGImage:image]; 56 | CGImageRelease(image); 57 | 58 | return image; 59 | } 60 | 61 | - (CGImageRef)cachedImageForPageIndex:(NSUInteger)pageIndex { 62 | NSNumber *pageIndexNumber = [NSNumber numberWithInt:pageIndex]; 63 | UIImage *pageImage; 64 | @synchronized (self.pageCache) { 65 | pageImage = [self.pageCache objectForKey:pageIndexNumber]; 66 | } 67 | if (!pageImage) { 68 | CGImageRef pageCGImage = [self imageForPageIndex:pageIndex]; 69 | if (pageCGImage) { 70 | pageImage = [UIImage imageWithCGImage:pageCGImage]; 71 | @synchronized (self.pageCache) { 72 | [self.pageCache setObject:pageImage forKey:pageIndexNumber]; 73 | } 74 | } 75 | } 76 | return pageImage.CGImage; 77 | } 78 | 79 | - (void)precacheImageForPageIndexNumber:(NSNumber *)pageIndexNumber { 80 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 81 | [self cachedImageForPageIndex:[pageIndexNumber intValue]]; 82 | [pool release]; 83 | } 84 | 85 | - (void)precacheImageForPageIndex:(NSUInteger)pageIndex { 86 | [self performSelectorInBackground:@selector(precacheImageForPageIndexNumber:) 87 | withObject:[NSNumber numberWithInt:pageIndex]]; 88 | } 89 | 90 | - (void)minimizeToPageIndex:(NSUInteger)pageIndex { 91 | /* Uncache all pages except previous, current, and next. */ 92 | @synchronized (self.pageCache) { 93 | for (NSNumber *key in [self.pageCache allKeys]) 94 | if (ABS([key intValue] - (int)pageIndex) > 2) 95 | [self.pageCache removeObjectForKey:key]; 96 | } 97 | } 98 | 99 | - (void)flush { 100 | @synchronized (self.pageCache) { 101 | [self.pageCache removeAllObjects]; 102 | } 103 | } 104 | 105 | #pragma mark accessors 106 | 107 | - (void)setPageSize:(CGSize)value { 108 | _pageSize = value; 109 | [self flush]; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Leaves/LeavesView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesView.h 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol LeavesViewDataSource; 12 | @protocol LeavesViewDelegate; 13 | 14 | // This view displays a sequence of pages, one at a time. The user navigates 15 | // forward and backward through the sequence using a page-turn gesture or by 16 | // tapping invisible targets on the left and right margins of the current page. 17 | // 18 | // Pages are non-interactive raster images supplied by a data source that 19 | // conforms to the LeavesViewDataSource protocol. 20 | // 21 | // An optional delegate, conforming to the LeavesViewDelegate protocol, is 22 | // notified when the page is turned. 23 | @interface LeavesView : UIView 24 | 25 | @property (assign) id dataSource; 26 | @property (assign) id delegate; 27 | 28 | // The width of the invisible targets in the left and right margins, which may 29 | // be tapped to turn to the previous and next page respectively. 30 | // 31 | // This value is chosen automatically based on the view's frame unless the 32 | // preferredTargetWidth property is set to a nonzero value. 33 | @property (readonly) CGFloat targetWidth; 34 | 35 | // If this is set to a nonzero value, it will override the value chosen 36 | // automatically for targetWidth. 37 | // 38 | // The default value of this property is 0. 39 | @property (nonatomic, assign) CGFloat preferredTargetWidth; 40 | 41 | // The zero-based index of the page currently displayed. The value of this 42 | // property changes when the user turns the page. You may also set this value 43 | // programmatically to jump to a certain page. 44 | @property (nonatomic, assign) NSUInteger currentPageIndex; 45 | 46 | // If this property is set to YES, pages likely to be displayed soon will be 47 | // pre-rendered in a background thread to avoid blocking the main thread when 48 | // the page is turned. Only set this to YES if your implementation of the data 49 | // source methods is thread-safe. 50 | // 51 | // The defaut value of this property is NO. 52 | @property (assign) BOOL backgroundRendering; 53 | 54 | // Reload content from the data source. This also resets the currentPageIndex 55 | // property to 0 and jumps to the first page. 56 | - (void)reloadData; 57 | 58 | @end 59 | 60 | @protocol LeavesViewDataSource 61 | 62 | // Returns the total number of pages to be displayed. 63 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView; 64 | 65 | // Draws the content of the given page in the given Core Graphics context. Your 66 | // implementation should draw within the bounding box returned by 67 | // CGContextGetClipBoundingBox(context). 68 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)context; 69 | 70 | @end 71 | 72 | @protocol LeavesViewDelegate 73 | @optional 74 | 75 | // Called when the user triggers a page turn by touching up in the left or right 76 | // margin, or by completing a page-turn gesture. 77 | - (void)leavesView:(LeavesView *)leavesView willTurnToPageAtIndex:(NSUInteger)pageIndex; 78 | 79 | // Called when the animation accompanying a page turn completes. 80 | - (void)leavesView:(LeavesView *)leavesView didTurnToPageAtIndex:(NSUInteger)pageIndex; 81 | 82 | @end 83 | 84 | -------------------------------------------------------------------------------- /Leaves/LeavesView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesView.m 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "LeavesView.h" 10 | #import "LeavesCache.h" 11 | 12 | @interface LeavesView () 13 | 14 | @property (readonly) CALayer *topPage, *topPageOverlay, *topPageReverse, 15 | *topPageReverseImage, *topPageReverseOverlay, *bottomPage; 16 | @property (readonly) CAGradientLayer *topPageShadow, *topPageReverseShading, 17 | *bottomPageShadow; 18 | @property (nonatomic, assign) NSUInteger numberOfPages; 19 | @property (nonatomic, assign) CGFloat leafEdge; 20 | @property (nonatomic, assign) CGSize pageSize; 21 | @property (nonatomic, assign) CGPoint touchBeganPoint; 22 | @property (nonatomic, assign) CGRect nextPageRect, prevPageRect; 23 | @property (nonatomic, assign) BOOL touchIsActive, interactionLocked; 24 | @property (readonly) LeavesCache *pageCache; 25 | 26 | @end 27 | 28 | CGFloat distance(CGPoint a, CGPoint b); 29 | 30 | @implementation LeavesView 31 | 32 | - (void)initCommon { 33 | self.clipsToBounds = YES; 34 | 35 | _topPage = [[CALayer alloc] init]; 36 | _topPage.masksToBounds = YES; 37 | _topPage.contentsGravity = kCAGravityLeft; 38 | _topPage.backgroundColor = [[UIColor whiteColor] CGColor]; 39 | 40 | _topPageOverlay = [[CALayer alloc] init]; 41 | _topPageOverlay.backgroundColor = [[[UIColor blackColor] colorWithAlphaComponent:0.2] CGColor]; 42 | 43 | _topPageShadow = [[CAGradientLayer alloc] init]; 44 | _topPageShadow.colors = [NSArray arrayWithObjects: 45 | (id)[[[UIColor blackColor] colorWithAlphaComponent:0.6] CGColor], 46 | (id)[[UIColor clearColor] CGColor], 47 | nil]; 48 | _topPageShadow.startPoint = CGPointMake(1,0.5); 49 | _topPageShadow.endPoint = CGPointMake(0,0.5); 50 | 51 | _topPageReverse = [[CALayer alloc] init]; 52 | _topPageReverse.backgroundColor = [[UIColor whiteColor] CGColor]; 53 | _topPageReverse.masksToBounds = YES; 54 | 55 | _topPageReverseImage = [[CALayer alloc] init]; 56 | _topPageReverseImage.masksToBounds = YES; 57 | _topPageReverseImage.contentsGravity = kCAGravityRight; 58 | 59 | _topPageReverseOverlay = [[CALayer alloc] init]; 60 | _topPageReverseOverlay.backgroundColor = [[[UIColor whiteColor] colorWithAlphaComponent:0.8] CGColor]; 61 | 62 | _topPageReverseShading = [[CAGradientLayer alloc] init]; 63 | _topPageReverseShading.colors = [NSArray arrayWithObjects: 64 | (id)[[[UIColor blackColor] colorWithAlphaComponent:0.6] CGColor], 65 | (id)[[UIColor clearColor] CGColor], 66 | nil]; 67 | _topPageReverseShading.startPoint = CGPointMake(1,0.5); 68 | _topPageReverseShading.endPoint = CGPointMake(0,0.5); 69 | 70 | _bottomPage = [[CALayer alloc] init]; 71 | _bottomPage.backgroundColor = [[UIColor whiteColor] CGColor]; 72 | _bottomPage.masksToBounds = YES; 73 | 74 | _bottomPageShadow = [[CAGradientLayer alloc] init]; 75 | _bottomPageShadow.colors = [NSArray arrayWithObjects: 76 | (id)[[[UIColor blackColor] colorWithAlphaComponent:0.6] CGColor], 77 | (id)[[UIColor clearColor] CGColor], 78 | nil]; 79 | _bottomPageShadow.startPoint = CGPointMake(0,0.5); 80 | _bottomPageShadow.endPoint = CGPointMake(1,0.5); 81 | 82 | [_topPage addSublayer:_topPageShadow]; 83 | [_topPage addSublayer:_topPageOverlay]; 84 | [_topPageReverse addSublayer:_topPageReverseImage]; 85 | [_topPageReverse addSublayer:_topPageReverseOverlay]; 86 | [_topPageReverse addSublayer:_topPageReverseShading]; 87 | [_bottomPage addSublayer:_bottomPageShadow]; 88 | [self.layer addSublayer:_bottomPage]; 89 | [self.layer addSublayer:_topPage]; 90 | [self.layer addSublayer:_topPageReverse]; 91 | 92 | _leafEdge = 1.0; 93 | _backgroundRendering = NO; 94 | _pageCache = [[LeavesCache alloc] initWithPageSize:self.bounds.size]; 95 | } 96 | 97 | - (id)initWithFrame:(CGRect)frame { 98 | if ((self = [super initWithFrame:frame])) { 99 | [self initCommon]; 100 | } 101 | return self; 102 | } 103 | 104 | - (id)initWithCoder:(NSCoder *)aDecoder { 105 | if (self = [super initWithCoder:aDecoder]) { 106 | [self initCommon]; 107 | } 108 | return self; 109 | } 110 | 111 | - (void)dealloc { 112 | [_topPage release]; 113 | [_topPageShadow release]; 114 | [_topPageOverlay release]; 115 | [_topPageReverse release]; 116 | [_topPageReverseImage release]; 117 | [_topPageReverseOverlay release]; 118 | [_topPageReverseShading release]; 119 | [_bottomPage release]; 120 | [_bottomPageShadow release]; 121 | [_pageCache release]; 122 | 123 | [super dealloc]; 124 | } 125 | 126 | - (void)reloadData { 127 | [self.pageCache flush]; 128 | self.numberOfPages = [self.pageCache.dataSource numberOfPagesInLeavesView:self]; 129 | self.currentPageIndex = 0; 130 | } 131 | 132 | - (void)getImages { 133 | if (self.currentPageIndex < self.numberOfPages) { 134 | if (self.currentPageIndex > 0 && self.backgroundRendering) 135 | [self.pageCache precacheImageForPageIndex:self.currentPageIndex-1]; 136 | self.topPage.contents = (id)[self.pageCache cachedImageForPageIndex:self.currentPageIndex]; 137 | self.topPageReverseImage.contents = (id)[self.pageCache cachedImageForPageIndex:self.currentPageIndex]; 138 | if (self.currentPageIndex < self.numberOfPages - 1) 139 | self.bottomPage.contents = (id)[self.pageCache cachedImageForPageIndex:self.currentPageIndex + 1]; 140 | [self.pageCache minimizeToPageIndex:self.currentPageIndex]; 141 | } else { 142 | self.topPage.contents = nil; 143 | self.topPageReverseImage.contents = nil; 144 | self.bottomPage.contents = nil; 145 | } 146 | } 147 | 148 | - (void)setLayerFrames { 149 | self.topPage.frame = CGRectMake(self.layer.bounds.origin.x, 150 | self.layer.bounds.origin.y, 151 | self.leafEdge * self.bounds.size.width, 152 | self.layer.bounds.size.height); 153 | self.topPageReverse.frame = CGRectMake(self.layer.bounds.origin.x + (2*self.leafEdge-1) * self.bounds.size.width, 154 | self.layer.bounds.origin.y, 155 | (1-self.leafEdge) * self.bounds.size.width, 156 | self.layer.bounds.size.height); 157 | self.bottomPage.frame = self.layer.bounds; 158 | self.topPageShadow.frame = CGRectMake(self.topPageReverse.frame.origin.x - 40, 159 | 0, 160 | 40, 161 | self.bottomPage.bounds.size.height); 162 | self.topPageReverseImage.frame = self.topPageReverse.bounds; 163 | self.topPageReverseImage.transform = CATransform3DMakeScale(-1, 1, 1); 164 | self.topPageReverseOverlay.frame = self.topPageReverse.bounds; 165 | self.topPageReverseShading.frame = CGRectMake(self.topPageReverse.bounds.size.width - 50, 166 | 0, 167 | 50 + 1, 168 | self.topPageReverse.bounds.size.height); 169 | self.bottomPageShadow.frame = CGRectMake(self.leafEdge * self.bounds.size.width, 170 | 0, 171 | 40, 172 | self.bottomPage.bounds.size.height); 173 | self.topPageOverlay.frame = self.topPage.bounds; 174 | } 175 | 176 | - (void)willTurnToPageAtIndex:(NSUInteger)index { 177 | if ([self.delegate respondsToSelector:@selector(leavesView:willTurnToPageAtIndex:)]) 178 | [self.delegate leavesView:self willTurnToPageAtIndex:index]; 179 | } 180 | 181 | - (void)didTurnToPageAtIndex:(NSUInteger)index { 182 | if ([self.delegate respondsToSelector:@selector(leavesView:didTurnToPageAtIndex:)]) 183 | [self.delegate leavesView:self didTurnToPageAtIndex:index]; 184 | } 185 | 186 | - (void)didTurnPageBackward { 187 | self.interactionLocked = NO; 188 | [self didTurnToPageAtIndex:self.currentPageIndex]; 189 | } 190 | 191 | - (void)didTurnPageForward { 192 | self.interactionLocked = NO; 193 | self.currentPageIndex = self.currentPageIndex + 1; 194 | [self didTurnToPageAtIndex:self.currentPageIndex]; 195 | } 196 | 197 | - (BOOL)hasPrevPage { 198 | return self.currentPageIndex > 0; 199 | } 200 | 201 | - (BOOL)hasNextPage { 202 | return self.currentPageIndex < self.numberOfPages - 1; 203 | } 204 | 205 | - (BOOL)touchedNextPage { 206 | return CGRectContainsPoint(self.nextPageRect, self.touchBeganPoint); 207 | } 208 | 209 | - (BOOL)touchedPrevPage { 210 | return CGRectContainsPoint(self.prevPageRect, self.touchBeganPoint); 211 | } 212 | 213 | - (CGFloat)dragThreshold { 214 | // Magic empirical number 215 | return 10; 216 | } 217 | 218 | - (CGFloat)targetWidth { 219 | // Magic empirical formula 220 | if (self.preferredTargetWidth > 0 && self.preferredTargetWidth < self.bounds.size.width / 2) 221 | return self.preferredTargetWidth; 222 | else 223 | return MAX(28, self.bounds.size.width / 5); 224 | } 225 | 226 | - (void)updateTargetRects { 227 | CGFloat targetWidth = [self targetWidth]; 228 | self.nextPageRect = CGRectMake(self.bounds.size.width - targetWidth, 229 | 0, 230 | targetWidth, 231 | self.bounds.size.height); 232 | self.prevPageRect = CGRectMake(0, 233 | 0, 234 | targetWidth, 235 | self.bounds.size.height); 236 | } 237 | 238 | #pragma mark accessors 239 | 240 | - (id)dataSource { 241 | return self.pageCache.dataSource; 242 | 243 | } 244 | 245 | - (void)setDataSource:(id)value { 246 | self.pageCache.dataSource = value; 247 | } 248 | 249 | - (void)setLeafEdge:(CGFloat)aLeafEdge { 250 | _leafEdge = aLeafEdge; 251 | self.topPageShadow.opacity = MIN(1.0, 4*(1-self.leafEdge)); 252 | self.bottomPageShadow.opacity = MIN(1.0, 4*self.leafEdge); 253 | self.topPageOverlay.opacity = MIN(1.0, 4*(1-self.leafEdge)); 254 | [self setLayerFrames]; 255 | } 256 | 257 | - (void)setCurrentPageIndex:(NSUInteger)aCurrentPageIndex { 258 | _currentPageIndex = aCurrentPageIndex; 259 | 260 | [CATransaction begin]; 261 | [CATransaction setValue:(id)kCFBooleanTrue 262 | forKey:kCATransactionDisableActions]; 263 | 264 | [self getImages]; 265 | 266 | self.leafEdge = 1.0; 267 | 268 | [CATransaction commit]; 269 | } 270 | 271 | - (void)setPreferredTargetWidth:(CGFloat)value { 272 | _preferredTargetWidth = value; 273 | [self updateTargetRects]; 274 | } 275 | 276 | #pragma mark UIResponder 277 | 278 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 279 | if (self.interactionLocked) 280 | return; 281 | 282 | UITouch *touch = [event.allTouches anyObject]; 283 | self.touchBeganPoint = [touch locationInView:self]; 284 | 285 | if ([self touchedPrevPage] && [self hasPrevPage]) { 286 | [CATransaction begin]; 287 | [CATransaction setValue:(id)kCFBooleanTrue 288 | forKey:kCATransactionDisableActions]; 289 | self.currentPageIndex = self.currentPageIndex - 1; 290 | self.leafEdge = 0.0; 291 | [CATransaction commit]; 292 | self.touchIsActive = YES; 293 | } 294 | else if ([self touchedNextPage] && [self hasNextPage]) 295 | self.touchIsActive = YES; 296 | 297 | else 298 | self.touchIsActive = NO; 299 | } 300 | 301 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 302 | if (!self.touchIsActive) 303 | return; 304 | UITouch *touch = [event.allTouches anyObject]; 305 | CGPoint touchPoint = [touch locationInView:self]; 306 | 307 | [CATransaction begin]; 308 | [CATransaction setValue:[NSNumber numberWithFloat:0.07] 309 | forKey:kCATransactionAnimationDuration]; 310 | self.leafEdge = touchPoint.x / self.bounds.size.width; 311 | [CATransaction commit]; 312 | } 313 | 314 | 315 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 316 | if (!self.touchIsActive) 317 | return; 318 | self.touchIsActive = NO; 319 | 320 | UITouch *touch = [event.allTouches anyObject]; 321 | CGPoint touchPoint = [touch locationInView:self]; 322 | BOOL dragged = distance(touchPoint, self.touchBeganPoint) > [self dragThreshold]; 323 | 324 | [CATransaction begin]; 325 | float duration; 326 | if ((dragged && self.leafEdge < 0.5) || (!dragged && [self touchedNextPage])) { 327 | [self willTurnToPageAtIndex:self.currentPageIndex+1]; 328 | self.leafEdge = 0; 329 | duration = self.leafEdge; 330 | self.interactionLocked = YES; 331 | if (self.currentPageIndex+2 < self.numberOfPages && self.backgroundRendering) 332 | [self.pageCache precacheImageForPageIndex:self.currentPageIndex+2]; 333 | [self performSelector:@selector(didTurnPageForward) 334 | withObject:nil 335 | afterDelay:duration + 0.25]; 336 | } 337 | else { 338 | [self willTurnToPageAtIndex:self.currentPageIndex]; 339 | self.leafEdge = 1.0; 340 | duration = 1 - self.leafEdge; 341 | self.interactionLocked = YES; 342 | [self performSelector:@selector(didTurnPageBackward) 343 | withObject:nil 344 | afterDelay:duration + 0.25]; 345 | } 346 | [CATransaction setValue:[NSNumber numberWithFloat:duration] 347 | forKey:kCATransactionAnimationDuration]; 348 | [CATransaction commit]; 349 | } 350 | 351 | - (void)layoutSubviews { 352 | [super layoutSubviews]; 353 | 354 | if (!CGSizeEqualToSize(self.pageSize, self.bounds.size)) { 355 | self.pageSize = self.bounds.size; 356 | 357 | [CATransaction begin]; 358 | [CATransaction setValue:(id)kCFBooleanTrue 359 | forKey:kCATransactionDisableActions]; 360 | [self setLayerFrames]; 361 | [CATransaction commit]; 362 | 363 | self.pageCache.pageSize = self.bounds.size; 364 | [self getImages]; 365 | [self updateTargetRects]; 366 | } 367 | } 368 | 369 | @end 370 | 371 | CGFloat distance(CGPoint a, CGPoint b) { 372 | return sqrtf(powf(a.x-b.x, 2) + powf(a.y-b.y, 2)); 373 | } 374 | -------------------------------------------------------------------------------- /Leaves/LeavesViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesViewController.h 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright Tom Brow 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class LeavesView; 12 | 13 | // This view controller presents a LeavesView that occupies its entire view, and 14 | // whose data source and delegate are the view controller itself. 15 | // 16 | // Subclasses should provide content by overriding the view controller's 17 | // implementation of the LeavesViewDataSource protocol. 18 | @interface LeavesViewController : UIViewController 19 | 20 | // The LeavesView presented by the view controller. 21 | @property (readonly) LeavesView *leavesView; 22 | 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /Leaves/LeavesViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesViewController.m 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright Tom Brow 2010. All rights reserved. 7 | // 8 | 9 | #import "LeavesViewController.h" 10 | #import "LeavesView.h" 11 | 12 | @interface LeavesViewController () 13 | 14 | @end 15 | 16 | @implementation LeavesViewController 17 | 18 | - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle { 19 | if (self = [super initWithNibName:nibName bundle:nibBundle]) { 20 | _leavesView = [[LeavesView alloc] initWithFrame:CGRectZero]; 21 | _leavesView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 22 | _leavesView.dataSource = self; 23 | _leavesView.delegate = self; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)dealloc { 29 | [_leavesView release]; 30 | [super dealloc]; 31 | } 32 | 33 | #pragma mark LeavesViewDataSource 34 | 35 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView { 36 | return 0; 37 | } 38 | 39 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 40 | 41 | } 42 | 43 | #pragma mark UIViewController 44 | 45 | - (void)viewDidLoad { 46 | [super viewDidLoad]; 47 | 48 | _leavesView.frame = self.view.bounds; 49 | [self.view addSubview:_leavesView]; 50 | [_leavesView reloadData]; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /LeavesExamples.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 11 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 12 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 13 | D337E308119B61A5003E5728 /* LeavesCache.m in Sources */ = {isa = PBXBuildFile; fileRef = D337E307119B61A5003E5728 /* LeavesCache.m */; }; 14 | D33D45A2117BDE0100BA7203 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D33D45A1117BDE0100BA7203 /* QuartzCore.framework */; }; 15 | D33D4E5B117D818100BA7203 /* LeavesView.m in Sources */ = {isa = PBXBuildFile; fileRef = D33D4E58117D818100BA7203 /* LeavesView.m */; }; 16 | D33D4E5C117D818100BA7203 /* LeavesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D33D4E5A117D818100BA7203 /* LeavesViewController.m */; }; 17 | EA97678A17EB8E3C001A0F1C /* ExamplesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97677317EB8E3C001A0F1C /* ExamplesViewController.m */; }; 18 | EA97678B17EB8E3C001A0F1C /* ImageExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97677517EB8E3C001A0F1C /* ImageExampleViewController.m */; }; 19 | EA97678C17EB8E3C001A0F1C /* LeavesAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97677717EB8E3C001A0F1C /* LeavesAppDelegate.m */; }; 20 | EA97678D17EB8E3C001A0F1C /* PDFExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97677917EB8E3C001A0F1C /* PDFExampleViewController.m */; }; 21 | EA97678E17EB8E3C001A0F1C /* ProceduralExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97677B17EB8E3C001A0F1C /* ProceduralExampleViewController.m */; }; 22 | EA97679117EB8E3C001A0F1C /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EA97678217EB8E3C001A0F1C /* Default-568h@2x.png */; }; 23 | EA97679217EB8E3C001A0F1C /* kitten.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EA97678317EB8E3C001A0F1C /* kitten.jpg */; }; 24 | EA97679317EB8E3C001A0F1C /* kitten2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EA97678417EB8E3C001A0F1C /* kitten2.jpg */; }; 25 | EA97679417EB8E3C001A0F1C /* kitten3.jpg in Resources */ = {isa = PBXBuildFile; fileRef = EA97678517EB8E3C001A0F1C /* kitten3.jpg */; }; 26 | EA97679617EB8E3C001A0F1C /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = EA97678717EB8E3C001A0F1C /* MainWindow-iPad.xib */; }; 27 | EA97679717EB8E3C001A0F1C /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = EA97678817EB8E3C001A0F1C /* MainWindow.xib */; }; 28 | EA97679817EB8E3C001A0F1C /* paper.pdf in Resources */ = {isa = PBXBuildFile; fileRef = EA97678917EB8E3C001A0F1C /* paper.pdf */; }; 29 | EA97679B17EB8FAB001A0F1C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97679A17EB8FAB001A0F1C /* main.m */; }; 30 | EA97679E17EB8FB2001A0F1C /* Utilities.m in Sources */ = {isa = PBXBuildFile; fileRef = EA97679D17EB8FB2001A0F1C /* Utilities.m */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 35 | 1D6058910D05DD3D006BFB54 /* LeavesExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LeavesExamples.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 37 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 38 | D337E306119B61A5003E5728 /* LeavesCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeavesCache.h; sourceTree = ""; }; 39 | D337E307119B61A5003E5728 /* LeavesCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LeavesCache.m; sourceTree = ""; }; 40 | D33D45A1117BDE0100BA7203 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 41 | D33D4E57117D818100BA7203 /* LeavesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeavesView.h; sourceTree = ""; }; 42 | D33D4E58117D818100BA7203 /* LeavesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LeavesView.m; sourceTree = ""; }; 43 | D33D4E59117D818100BA7203 /* LeavesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeavesViewController.h; sourceTree = ""; }; 44 | D33D4E5A117D818100BA7203 /* LeavesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LeavesViewController.m; sourceTree = ""; }; 45 | EA97677217EB8E3C001A0F1C /* ExamplesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExamplesViewController.h; sourceTree = ""; }; 46 | EA97677317EB8E3C001A0F1C /* ExamplesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExamplesViewController.m; sourceTree = ""; }; 47 | EA97677417EB8E3C001A0F1C /* ImageExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageExampleViewController.h; sourceTree = ""; }; 48 | EA97677517EB8E3C001A0F1C /* ImageExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageExampleViewController.m; sourceTree = ""; }; 49 | EA97677617EB8E3C001A0F1C /* LeavesAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeavesAppDelegate.h; sourceTree = ""; }; 50 | EA97677717EB8E3C001A0F1C /* LeavesAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LeavesAppDelegate.m; sourceTree = ""; }; 51 | EA97677817EB8E3C001A0F1C /* PDFExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PDFExampleViewController.h; sourceTree = ""; }; 52 | EA97677917EB8E3C001A0F1C /* PDFExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PDFExampleViewController.m; sourceTree = ""; }; 53 | EA97677A17EB8E3C001A0F1C /* ProceduralExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProceduralExampleViewController.h; sourceTree = ""; }; 54 | EA97677B17EB8E3C001A0F1C /* ProceduralExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProceduralExampleViewController.m; sourceTree = ""; }; 55 | EA97678217EB8E3C001A0F1C /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 56 | EA97678317EB8E3C001A0F1C /* kitten.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = kitten.jpg; sourceTree = ""; }; 57 | EA97678417EB8E3C001A0F1C /* kitten2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = kitten2.jpg; sourceTree = ""; }; 58 | EA97678517EB8E3C001A0F1C /* kitten3.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = kitten3.jpg; sourceTree = ""; }; 59 | EA97678617EB8E3C001A0F1C /* LeavesExamples-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "LeavesExamples-Info.plist"; sourceTree = ""; }; 60 | EA97678717EB8E3C001A0F1C /* MainWindow-iPad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "MainWindow-iPad.xib"; sourceTree = ""; }; 61 | EA97678817EB8E3C001A0F1C /* MainWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 62 | EA97678917EB8E3C001A0F1C /* paper.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = paper.pdf; sourceTree = ""; }; 63 | EA97679917EB8FAB001A0F1C /* LeavesExamples_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LeavesExamples_Prefix.pch; path = LeavesExamples/LeavesExamples_Prefix.pch; sourceTree = SOURCE_ROOT; }; 64 | EA97679A17EB8FAB001A0F1C /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = LeavesExamples/main.m; sourceTree = SOURCE_ROOT; }; 65 | EA97679C17EB8FB2001A0F1C /* Utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utilities.h; path = LeavesExamples/Other/Utilities.h; sourceTree = SOURCE_ROOT; }; 66 | EA97679D17EB8FB2001A0F1C /* Utilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Utilities.m; path = LeavesExamples/Other/Utilities.m; sourceTree = SOURCE_ROOT; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 75 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 76 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 77 | D33D45A2117BDE0100BA7203 /* QuartzCore.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 1D6058910D05DD3D006BFB54 /* LeavesExamples.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | D33D4E56117D818100BA7203 /* Leaves */, 96 | EA97677117EB8E3C001A0F1C /* Classes */, 97 | EA97677C17EB8E3C001A0F1C /* Other Sources */, 98 | EA97678117EB8E3C001A0F1C /* Resources */, 99 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 100 | 19C28FACFE9D520D11CA2CBB /* Products */, 101 | ); 102 | name = CustomTemplate; 103 | sourceTree = ""; 104 | }; 105 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 109 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 110 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 111 | D33D45A1117BDE0100BA7203 /* QuartzCore.framework */, 112 | ); 113 | name = Frameworks; 114 | sourceTree = ""; 115 | }; 116 | D33D4E56117D818100BA7203 /* Leaves */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | D337E306119B61A5003E5728 /* LeavesCache.h */, 120 | D337E307119B61A5003E5728 /* LeavesCache.m */, 121 | D33D4E57117D818100BA7203 /* LeavesView.h */, 122 | D33D4E58117D818100BA7203 /* LeavesView.m */, 123 | D33D4E59117D818100BA7203 /* LeavesViewController.h */, 124 | D33D4E5A117D818100BA7203 /* LeavesViewController.m */, 125 | ); 126 | path = Leaves; 127 | sourceTree = ""; 128 | }; 129 | EA97677117EB8E3C001A0F1C /* Classes */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | EA97677217EB8E3C001A0F1C /* ExamplesViewController.h */, 133 | EA97677317EB8E3C001A0F1C /* ExamplesViewController.m */, 134 | EA97677417EB8E3C001A0F1C /* ImageExampleViewController.h */, 135 | EA97677517EB8E3C001A0F1C /* ImageExampleViewController.m */, 136 | EA97677617EB8E3C001A0F1C /* LeavesAppDelegate.h */, 137 | EA97677717EB8E3C001A0F1C /* LeavesAppDelegate.m */, 138 | EA97677817EB8E3C001A0F1C /* PDFExampleViewController.h */, 139 | EA97677917EB8E3C001A0F1C /* PDFExampleViewController.m */, 140 | EA97677A17EB8E3C001A0F1C /* ProceduralExampleViewController.h */, 141 | EA97677B17EB8E3C001A0F1C /* ProceduralExampleViewController.m */, 142 | ); 143 | name = Classes; 144 | path = LeavesExamples/Classes; 145 | sourceTree = ""; 146 | }; 147 | EA97677C17EB8E3C001A0F1C /* Other Sources */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | EA97679917EB8FAB001A0F1C /* LeavesExamples_Prefix.pch */, 151 | EA97679A17EB8FAB001A0F1C /* main.m */, 152 | EA97679C17EB8FB2001A0F1C /* Utilities.h */, 153 | EA97679D17EB8FB2001A0F1C /* Utilities.m */, 154 | ); 155 | name = "Other Sources"; 156 | path = "LeavesExamples/Other Sources"; 157 | sourceTree = ""; 158 | }; 159 | EA97678117EB8E3C001A0F1C /* Resources */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | EA97678217EB8E3C001A0F1C /* Default-568h@2x.png */, 163 | EA97678317EB8E3C001A0F1C /* kitten.jpg */, 164 | EA97678417EB8E3C001A0F1C /* kitten2.jpg */, 165 | EA97678517EB8E3C001A0F1C /* kitten3.jpg */, 166 | EA97678617EB8E3C001A0F1C /* LeavesExamples-Info.plist */, 167 | EA97678717EB8E3C001A0F1C /* MainWindow-iPad.xib */, 168 | EA97678817EB8E3C001A0F1C /* MainWindow.xib */, 169 | EA97678917EB8E3C001A0F1C /* paper.pdf */, 170 | ); 171 | name = Resources; 172 | path = LeavesExamples/Resources; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXGroup section */ 176 | 177 | /* Begin PBXNativeTarget section */ 178 | 1D6058900D05DD3D006BFB54 /* LeavesExamples */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "LeavesExamples" */; 181 | buildPhases = ( 182 | 1D60588D0D05DD3D006BFB54 /* Resources */, 183 | 1D60588E0D05DD3D006BFB54 /* Sources */, 184 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = LeavesExamples; 191 | productName = Leaves; 192 | productReference = 1D6058910D05DD3D006BFB54 /* LeavesExamples.app */; 193 | productType = "com.apple.product-type.application"; 194 | }; 195 | /* End PBXNativeTarget section */ 196 | 197 | /* Begin PBXProject section */ 198 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 199 | isa = PBXProject; 200 | attributes = { 201 | LastUpgradeCheck = 0500; 202 | ORGANIZATIONNAME = "Tom Brow"; 203 | }; 204 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "LeavesExamples" */; 205 | compatibilityVersion = "Xcode 3.2"; 206 | developmentRegion = English; 207 | hasScannedForEncodings = 1; 208 | knownRegions = ( 209 | en, 210 | ); 211 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 212 | projectDirPath = ""; 213 | projectRoot = ""; 214 | targets = ( 215 | 1D6058900D05DD3D006BFB54 /* LeavesExamples */, 216 | ); 217 | }; 218 | /* End PBXProject section */ 219 | 220 | /* Begin PBXResourcesBuildPhase section */ 221 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | EA97679717EB8E3C001A0F1C /* MainWindow.xib in Resources */, 226 | EA97679817EB8E3C001A0F1C /* paper.pdf in Resources */, 227 | EA97679417EB8E3C001A0F1C /* kitten3.jpg in Resources */, 228 | EA97679217EB8E3C001A0F1C /* kitten.jpg in Resources */, 229 | EA97679117EB8E3C001A0F1C /* Default-568h@2x.png in Resources */, 230 | EA97679617EB8E3C001A0F1C /* MainWindow-iPad.xib in Resources */, 231 | EA97679317EB8E3C001A0F1C /* kitten2.jpg in Resources */, 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | }; 235 | /* End PBXResourcesBuildPhase section */ 236 | 237 | /* Begin PBXSourcesBuildPhase section */ 238 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 239 | isa = PBXSourcesBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | EA97678E17EB8E3C001A0F1C /* ProceduralExampleViewController.m in Sources */, 243 | D33D4E5B117D818100BA7203 /* LeavesView.m in Sources */, 244 | EA97678A17EB8E3C001A0F1C /* ExamplesViewController.m in Sources */, 245 | EA97678D17EB8E3C001A0F1C /* PDFExampleViewController.m in Sources */, 246 | EA97679E17EB8FB2001A0F1C /* Utilities.m in Sources */, 247 | EA97678B17EB8E3C001A0F1C /* ImageExampleViewController.m in Sources */, 248 | D33D4E5C117D818100BA7203 /* LeavesViewController.m in Sources */, 249 | EA97678C17EB8E3C001A0F1C /* LeavesAppDelegate.m in Sources */, 250 | EA97679B17EB8FAB001A0F1C /* main.m in Sources */, 251 | D337E308119B61A5003E5728 /* LeavesCache.m in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | /* End PBXSourcesBuildPhase section */ 256 | 257 | /* Begin XCBuildConfiguration section */ 258 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ALWAYS_SEARCH_USER_PATHS = NO; 262 | COPY_PHASE_STRIP = NO; 263 | GCC_DYNAMIC_NO_PIC = NO; 264 | GCC_OPTIMIZATION_LEVEL = 0; 265 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 266 | INFOPLIST_FILE = "$(SRCROOT)/LeavesExamples/Resources/LeavesExamples-Info.plist"; 267 | PRODUCT_NAME = LeavesExamples; 268 | SDKROOT = iphoneos; 269 | TARGETED_DEVICE_FAMILY = "1,2"; 270 | }; 271 | name = Debug; 272 | }; 273 | 1D6058950D05DD3E006BFB54 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | COPY_PHASE_STRIP = YES; 278 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 279 | INFOPLIST_FILE = "$(SRCROOT)/LeavesExamples/Resources/LeavesExamples-Info.plist"; 280 | PRODUCT_NAME = LeavesExamples; 281 | SDKROOT = iphoneos; 282 | TARGETED_DEVICE_FAMILY = "1,2"; 283 | VALIDATE_PRODUCT = YES; 284 | }; 285 | name = Release; 286 | }; 287 | C01FCF4F08A954540054247B /* Debug */ = { 288 | isa = XCBuildConfiguration; 289 | buildSettings = { 290 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 291 | GCC_C_LANGUAGE_STANDARD = c99; 292 | GCC_PREFIX_HEADER = "$(SRCROOT)/LeavesExamples/LeavesExamples_Prefix.pch"; 293 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 3.2; 296 | ONLY_ACTIVE_ARCH = YES; 297 | PREBINDING = NO; 298 | SDKROOT = iphoneos; 299 | }; 300 | name = Debug; 301 | }; 302 | C01FCF5008A954540054247B /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 306 | GCC_C_LANGUAGE_STANDARD = c99; 307 | GCC_PREFIX_HEADER = "$(SRCROOT)/LeavesExamples/LeavesExamples_Prefix.pch"; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 3.2; 311 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 312 | PREBINDING = NO; 313 | SDKROOT = iphoneos; 314 | }; 315 | name = Release; 316 | }; 317 | /* End XCBuildConfiguration section */ 318 | 319 | /* Begin XCConfigurationList section */ 320 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "LeavesExamples" */ = { 321 | isa = XCConfigurationList; 322 | buildConfigurations = ( 323 | 1D6058940D05DD3E006BFB54 /* Debug */, 324 | 1D6058950D05DD3E006BFB54 /* Release */, 325 | ); 326 | defaultConfigurationIsVisible = 0; 327 | defaultConfigurationName = Release; 328 | }; 329 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "LeavesExamples" */ = { 330 | isa = XCConfigurationList; 331 | buildConfigurations = ( 332 | C01FCF4F08A954540054247B /* Debug */, 333 | C01FCF5008A954540054247B /* Release */, 334 | ); 335 | defaultConfigurationIsVisible = 0; 336 | defaultConfigurationName = Release; 337 | }; 338 | /* End XCConfigurationList section */ 339 | }; 340 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 341 | } 342 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ExamplesViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExamplesViewController.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/20/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExamplesViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ExamplesViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExamplesViewController.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/20/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "ExamplesViewController.h" 10 | #import "PDFExampleViewController.h" 11 | #import "ImageExampleViewController.h" 12 | #import "ProceduralExampleViewController.h" 13 | 14 | enum {ExamplePDF, ExampleImage, ExampleProcedural, NumExamples}; 15 | 16 | @implementation ExamplesViewController 17 | 18 | - (id)init { 19 | if (self = [super initWithStyle:UITableViewStyleGrouped]) { 20 | } 21 | return self; 22 | } 23 | 24 | #pragma mark UITableViewDataSource 25 | 26 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 27 | return 1; 28 | } 29 | 30 | 31 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 32 | return NumExamples; 33 | } 34 | 35 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 36 | 37 | static NSString *CellIdentifier = @"Cell"; 38 | 39 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 40 | if (cell == nil) { 41 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 42 | } 43 | 44 | switch (indexPath.row) { 45 | case ExamplePDF: cell.textLabel.text = @"PDF example"; break; 46 | case ExampleImage: cell.textLabel.text = @"Image example"; break; 47 | case ExampleProcedural: cell.textLabel.text = @"Procedural example"; break; 48 | default: cell.textLabel.text = @""; 49 | } 50 | return cell; 51 | } 52 | 53 | #pragma mark UITableViewDelegate 54 | 55 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 56 | UIViewController *viewController; 57 | switch (indexPath.row) { 58 | case ExamplePDF: 59 | viewController = [[[PDFExampleViewController alloc] init] autorelease]; 60 | break; 61 | case ExampleImage: 62 | viewController = [[[ImageExampleViewController alloc] init] autorelease]; 63 | break; 64 | case ExampleProcedural: 65 | viewController = [[[ProceduralExampleViewController alloc] init] autorelease]; 66 | break; 67 | default: 68 | viewController = nil; 69 | } 70 | 71 | if (viewController) 72 | [self.navigationController pushViewController:viewController animated:YES]; 73 | } 74 | 75 | 76 | @end 77 | 78 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ImageExampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "LeavesViewController.h" 10 | 11 | @interface ImageExampleViewController : LeavesViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ImageExampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.m 3 | // Leaves 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "ImageExampleViewController.h" 10 | #import "Utilities.h" 11 | 12 | @interface ImageExampleViewController () 13 | 14 | @property (readonly) NSArray *images; 15 | 16 | @end 17 | 18 | @implementation ImageExampleViewController 19 | 20 | - (id)init { 21 | if (self = [super init]) { 22 | _images = [[NSArray alloc] initWithObjects: 23 | [UIImage imageNamed:@"kitten.jpg"], 24 | [UIImage imageNamed:@"kitten2.jpg"], 25 | [UIImage imageNamed:@"kitten3.jpg"], 26 | nil]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)dealloc { 32 | [_images release]; 33 | [super dealloc]; 34 | } 35 | 36 | #pragma mark LeavesViewDataSource 37 | 38 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView { 39 | return _images.count; 40 | } 41 | 42 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 43 | UIImage *image = [_images objectAtIndex:index]; 44 | CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height); 45 | CGAffineTransform transform = aspectFit(imageRect, 46 | CGContextGetClipBoundingBox(ctx)); 47 | CGContextConcatCTM(ctx, transform); 48 | CGContextDrawImage(ctx, imageRect, [image CGImage]); 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/LeavesAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesAppDelegate.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright Tom Brow 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LeavesAppDelegate : NSObject 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/LeavesAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // LeavesAppDelegate.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright Tom Brow 2010. All rights reserved. 7 | // 8 | 9 | #import "LeavesAppDelegate.h" 10 | #import "ExamplesViewController.h" 11 | 12 | @implementation LeavesAppDelegate 13 | 14 | @synthesize window=_window; 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | UIViewController *rootViewController = [[[ExamplesViewController alloc] init] autorelease]; 18 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; 19 | [self.window makeKeyAndVisible]; 20 | 21 | return YES; 22 | } 23 | 24 | - (void)dealloc { 25 | [_window release]; 26 | [super dealloc]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/PDFExampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PDFExampleViewController.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/19/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "LeavesViewController.h" 10 | 11 | @interface PDFExampleViewController : LeavesViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/PDFExampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PDFExampleViewController.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/19/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "PDFExampleViewController.h" 10 | #import "Utilities.h" 11 | #import "LeavesView.h" 12 | 13 | @interface PDFExampleViewController () 14 | 15 | @property (readonly) CGPDFDocumentRef pdf; 16 | 17 | @end 18 | 19 | @implementation PDFExampleViewController 20 | 21 | - (id)init { 22 | if (self = [super init]) { 23 | CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("paper.pdf"), NULL, NULL); 24 | _pdf = CGPDFDocumentCreateWithURL(pdfURL); 25 | CFRelease(pdfURL); 26 | 27 | self.leavesView.backgroundRendering = YES; 28 | [self displayPageNumber:1]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)dealloc { 34 | CGPDFDocumentRelease(_pdf); 35 | [super dealloc]; 36 | } 37 | 38 | - (void)displayPageNumber:(NSUInteger)pageNumber { 39 | self.navigationItem.title = [NSString stringWithFormat: 40 | @"Page %u of %lu", 41 | pageNumber, 42 | CGPDFDocumentGetNumberOfPages(_pdf)]; 43 | } 44 | 45 | #pragma mark LeavesViewDelegate 46 | 47 | - (void)leavesView:(LeavesView *)leavesView willTurnToPageAtIndex:(NSUInteger)pageIndex { 48 | [self displayPageNumber:pageIndex + 1]; 49 | } 50 | 51 | #pragma mark LeavesViewDataSource 52 | 53 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView { 54 | return CGPDFDocumentGetNumberOfPages(_pdf); 55 | } 56 | 57 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 58 | CGPDFPageRef page = CGPDFDocumentGetPage(_pdf, index + 1); 59 | CGAffineTransform transform = aspectFit(CGPDFPageGetBoxRect(page, kCGPDFMediaBox), 60 | CGContextGetClipBoundingBox(ctx)); 61 | CGContextConcatCTM(ctx, transform); 62 | CGContextDrawPDFPage(ctx, page); 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ProceduralExampleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MinimalExampleViewController.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/20/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "LeavesViewController.h" 10 | 11 | @interface ProceduralExampleViewController : LeavesViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LeavesExamples/Classes/ProceduralExampleViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MinimalExampleViewController.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/20/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import "ProceduralExampleViewController.h" 10 | 11 | 12 | @implementation ProceduralExampleViewController 13 | 14 | #pragma mark LeavesViewDataSource 15 | 16 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView { 17 | return 10; 18 | } 19 | 20 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx { 21 | CGRect bounds = CGContextGetClipBoundingBox(ctx); 22 | CGContextSetFillColorWithColor(ctx, [[UIColor colorWithHue:index/10.0 23 | saturation:0.8 24 | brightness:0.8 25 | alpha:1.0] CGColor]); 26 | CGContextFillRect(ctx, CGRectInset(bounds, 100, 100)); 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /LeavesExamples/LeavesExamples_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'LeavesExamples' target in the 'LeavesExamples' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /LeavesExamples/Other/Utilities.h: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.h 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/19/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | CGAffineTransform aspectFit(CGRect innerRect, CGRect outerRect); 12 | -------------------------------------------------------------------------------- /LeavesExamples/Other/Utilities.m: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/19/10. 6 | // Copyright 2010 Tom Brow. All rights reserved. 7 | // 8 | 9 | CGAffineTransform aspectFit(CGRect innerRect, CGRect outerRect) { 10 | CGFloat scaleFactor = MIN(outerRect.size.width/innerRect.size.width, outerRect.size.height/innerRect.size.height); 11 | CGAffineTransform scale = CGAffineTransformMakeScale(scaleFactor, scaleFactor); 12 | CGRect scaledInnerRect = CGRectApplyAffineTransform(innerRect, scale); 13 | CGAffineTransform translation = 14 | CGAffineTransformMakeTranslation((outerRect.size.width - scaledInnerRect.size.width) / 2 - scaledInnerRect.origin.x, 15 | (outerRect.size.height - scaledInnerRect.size.height) / 2 - scaledInnerRect.origin.y); 16 | return CGAffineTransformConcat(scale, translation); 17 | } 18 | -------------------------------------------------------------------------------- /LeavesExamples/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/leaves/7f2fd7b5796efc5e46d3ac7a6e28edeea0440dc7/LeavesExamples/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /LeavesExamples/Resources/LeavesExamples-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | NSMainNibFile~ipad 30 | MainWindow-iPad 31 | 32 | 33 | -------------------------------------------------------------------------------- /LeavesExamples/Resources/MainWindow-iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10C540 6 | 762 7 | 1038.25 8 | 458.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 87 12 | 13 | 14 | 15 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 16 | 17 | 18 | 19 | 20 | IBFilesOwner 21 | IBIPadFramework 22 | 23 | 24 | IBFirstResponder 25 | IBIPadFramework 26 | 27 | 28 | IBIPadFramework 29 | 30 | 31 | 32 | 292 33 | {768, 1024} 34 | 35 | 1 36 | MCAxIDAAA 37 | 38 | NO 39 | NO 40 | 41 | 2 42 | 43 | IBIPadFramework 44 | YES 45 | 46 | 47 | 48 | 49 | 50 | 51 | delegate 52 | 53 | 54 | 55 | 4 56 | 57 | 58 | 59 | window 60 | 61 | 62 | 63 | 14 64 | 65 | 66 | 67 | 68 | 69 | 0 70 | 71 | 72 | 73 | 74 | 75 | -1 76 | 77 | 78 | File's Owner 79 | 80 | 81 | 3 82 | 83 | 84 | Leaves App Delegate 85 | 86 | 87 | -2 88 | 89 | 90 | 91 | 92 | 12 93 | 94 | 95 | 96 | 97 | 98 | 99 | UIApplication 100 | UIResponder 101 | {{525, 346}, {320, 480}} 102 | 103 | IBCocoaTouchFramework 104 | 105 | 106 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 107 | LeavesAppDelegate 108 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 109 | 110 | 111 | 112 | 113 | 114 | 14 115 | 116 | 117 | 118 | 119 | LeavesAppDelegate 120 | NSObject 121 | 122 | window 123 | UIWindow 124 | 125 | 126 | IBProjectSource 127 | Classes/LeavesAppDelegate.h 128 | 129 | 130 | 131 | LeavesAppDelegate 132 | NSObject 133 | 134 | IBUserSource 135 | 136 | 137 | 138 | 139 | 140 | 141 | NSObject 142 | 143 | IBFrameworkSource 144 | Foundation.framework/Headers/NSError.h 145 | 146 | 147 | 148 | NSObject 149 | 150 | IBFrameworkSource 151 | Foundation.framework/Headers/NSFileManager.h 152 | 153 | 154 | 155 | NSObject 156 | 157 | IBFrameworkSource 158 | Foundation.framework/Headers/NSKeyValueCoding.h 159 | 160 | 161 | 162 | NSObject 163 | 164 | IBFrameworkSource 165 | Foundation.framework/Headers/NSKeyValueObserving.h 166 | 167 | 168 | 169 | NSObject 170 | 171 | IBFrameworkSource 172 | Foundation.framework/Headers/NSKeyedArchiver.h 173 | 174 | 175 | 176 | NSObject 177 | 178 | IBFrameworkSource 179 | Foundation.framework/Headers/NSNetServices.h 180 | 181 | 182 | 183 | NSObject 184 | 185 | IBFrameworkSource 186 | Foundation.framework/Headers/NSObject.h 187 | 188 | 189 | 190 | NSObject 191 | 192 | IBFrameworkSource 193 | Foundation.framework/Headers/NSPort.h 194 | 195 | 196 | 197 | NSObject 198 | 199 | IBFrameworkSource 200 | Foundation.framework/Headers/NSRunLoop.h 201 | 202 | 203 | 204 | NSObject 205 | 206 | IBFrameworkSource 207 | Foundation.framework/Headers/NSStream.h 208 | 209 | 210 | 211 | NSObject 212 | 213 | IBFrameworkSource 214 | Foundation.framework/Headers/NSThread.h 215 | 216 | 217 | 218 | NSObject 219 | 220 | IBFrameworkSource 221 | Foundation.framework/Headers/NSURL.h 222 | 223 | 224 | 225 | NSObject 226 | 227 | IBFrameworkSource 228 | Foundation.framework/Headers/NSURLConnection.h 229 | 230 | 231 | 232 | NSObject 233 | 234 | IBFrameworkSource 235 | Foundation.framework/Headers/NSXMLParser.h 236 | 237 | 238 | 239 | NSObject 240 | 241 | IBFrameworkSource 242 | QuartzCore.framework/Headers/CAAnimation.h 243 | 244 | 245 | 246 | NSObject 247 | 248 | IBFrameworkSource 249 | QuartzCore.framework/Headers/CALayer.h 250 | 251 | 252 | 253 | NSObject 254 | 255 | IBFrameworkSource 256 | UIKit.framework/Headers/UIAccessibility.h 257 | 258 | 259 | 260 | NSObject 261 | 262 | IBFrameworkSource 263 | UIKit.framework/Headers/UINibLoading.h 264 | 265 | 266 | 267 | NSObject 268 | 269 | IBFrameworkSource 270 | UIKit.framework/Headers/UIResponder.h 271 | 272 | 273 | 274 | UIApplication 275 | UIResponder 276 | 277 | IBFrameworkSource 278 | UIKit.framework/Headers/UIApplication.h 279 | 280 | 281 | 282 | UIResponder 283 | NSObject 284 | 285 | 286 | 287 | UIView 288 | 289 | IBFrameworkSource 290 | UIKit.framework/Headers/UITextField.h 291 | 292 | 293 | 294 | UIView 295 | UIResponder 296 | 297 | IBFrameworkSource 298 | UIKit.framework/Headers/UIView.h 299 | 300 | 301 | 302 | UIWindow 303 | UIView 304 | 305 | IBFrameworkSource 306 | UIKit.framework/Headers/UIWindow.h 307 | 308 | 309 | 310 | 311 | 0 312 | IBIPadFramework 313 | 314 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 315 | 316 | 317 | YES 318 | ../Leaves.xcodeproj 319 | 3 320 | 87 321 | 322 | 323 | -------------------------------------------------------------------------------- /LeavesExamples/Resources/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 768 5 | 10C540 6 | 762 7 | 1038.25 8 | 458.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 87 12 | 13 | 14 | YES 15 | 16 | 17 | YES 18 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 19 | 20 | 21 | YES 22 | 23 | YES 24 | 25 | 26 | YES 27 | 28 | 29 | 30 | YES 31 | 32 | IBFilesOwner 33 | IBCocoaTouchFramework 34 | 35 | 36 | IBFirstResponder 37 | IBCocoaTouchFramework 38 | 39 | 40 | IBCocoaTouchFramework 41 | 42 | 43 | 44 | 292 45 | {320, 480} 46 | 47 | 1 48 | MCAxIDAAA 49 | 50 | NO 51 | NO 52 | 53 | IBCocoaTouchFramework 54 | YES 55 | 56 | 57 | 58 | 59 | YES 60 | 61 | 62 | delegate 63 | 64 | 65 | 66 | 4 67 | 68 | 69 | 70 | window 71 | 72 | 73 | 74 | 14 75 | 76 | 77 | 78 | 79 | YES 80 | 81 | 0 82 | 83 | 84 | 85 | 86 | 87 | -1 88 | 89 | 90 | File's Owner 91 | 92 | 93 | 3 94 | 95 | 96 | Leaves App Delegate 97 | 98 | 99 | -2 100 | 101 | 102 | 103 | 104 | 12 105 | 106 | 107 | 108 | 109 | 110 | 111 | YES 112 | 113 | YES 114 | -1.CustomClassName 115 | -2.CustomClassName 116 | 12.IBEditorWindowLastContentRect 117 | 12.IBPluginDependency 118 | 3.CustomClassName 119 | 3.IBPluginDependency 120 | 121 | 122 | YES 123 | UIApplication 124 | UIResponder 125 | {{525, 346}, {320, 480}} 126 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 127 | LeavesAppDelegate 128 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 129 | 130 | 131 | 132 | YES 133 | 134 | 135 | YES 136 | 137 | 138 | 139 | 140 | YES 141 | 142 | 143 | YES 144 | 145 | 146 | 147 | 14 148 | 149 | 150 | 151 | YES 152 | 153 | LeavesAppDelegate 154 | NSObject 155 | 156 | window 157 | UIWindow 158 | 159 | 160 | IBProjectSource 161 | Classes/LeavesAppDelegate.h 162 | 163 | 164 | 165 | LeavesAppDelegate 166 | NSObject 167 | 168 | IBUserSource 169 | 170 | 171 | 172 | 173 | 174 | YES 175 | 176 | NSObject 177 | 178 | IBFrameworkSource 179 | Foundation.framework/Headers/NSError.h 180 | 181 | 182 | 183 | NSObject 184 | 185 | IBFrameworkSource 186 | Foundation.framework/Headers/NSFileManager.h 187 | 188 | 189 | 190 | NSObject 191 | 192 | IBFrameworkSource 193 | Foundation.framework/Headers/NSKeyValueCoding.h 194 | 195 | 196 | 197 | NSObject 198 | 199 | IBFrameworkSource 200 | Foundation.framework/Headers/NSKeyValueObserving.h 201 | 202 | 203 | 204 | NSObject 205 | 206 | IBFrameworkSource 207 | Foundation.framework/Headers/NSKeyedArchiver.h 208 | 209 | 210 | 211 | NSObject 212 | 213 | IBFrameworkSource 214 | Foundation.framework/Headers/NSNetServices.h 215 | 216 | 217 | 218 | NSObject 219 | 220 | IBFrameworkSource 221 | Foundation.framework/Headers/NSObject.h 222 | 223 | 224 | 225 | NSObject 226 | 227 | IBFrameworkSource 228 | Foundation.framework/Headers/NSPort.h 229 | 230 | 231 | 232 | NSObject 233 | 234 | IBFrameworkSource 235 | Foundation.framework/Headers/NSRunLoop.h 236 | 237 | 238 | 239 | NSObject 240 | 241 | IBFrameworkSource 242 | Foundation.framework/Headers/NSStream.h 243 | 244 | 245 | 246 | NSObject 247 | 248 | IBFrameworkSource 249 | Foundation.framework/Headers/NSThread.h 250 | 251 | 252 | 253 | NSObject 254 | 255 | IBFrameworkSource 256 | Foundation.framework/Headers/NSURL.h 257 | 258 | 259 | 260 | NSObject 261 | 262 | IBFrameworkSource 263 | Foundation.framework/Headers/NSURLConnection.h 264 | 265 | 266 | 267 | NSObject 268 | 269 | IBFrameworkSource 270 | Foundation.framework/Headers/NSXMLParser.h 271 | 272 | 273 | 274 | NSObject 275 | 276 | IBFrameworkSource 277 | QuartzCore.framework/Headers/CAAnimation.h 278 | 279 | 280 | 281 | NSObject 282 | 283 | IBFrameworkSource 284 | QuartzCore.framework/Headers/CALayer.h 285 | 286 | 287 | 288 | NSObject 289 | 290 | IBFrameworkSource 291 | UIKit.framework/Headers/UIAccessibility.h 292 | 293 | 294 | 295 | NSObject 296 | 297 | IBFrameworkSource 298 | UIKit.framework/Headers/UINibLoading.h 299 | 300 | 301 | 302 | NSObject 303 | 304 | IBFrameworkSource 305 | UIKit.framework/Headers/UIResponder.h 306 | 307 | 308 | 309 | UIApplication 310 | UIResponder 311 | 312 | IBFrameworkSource 313 | UIKit.framework/Headers/UIApplication.h 314 | 315 | 316 | 317 | UIResponder 318 | NSObject 319 | 320 | 321 | 322 | UIView 323 | 324 | IBFrameworkSource 325 | UIKit.framework/Headers/UITextField.h 326 | 327 | 328 | 329 | UIView 330 | UIResponder 331 | 332 | IBFrameworkSource 333 | UIKit.framework/Headers/UIView.h 334 | 335 | 336 | 337 | UIWindow 338 | UIView 339 | 340 | IBFrameworkSource 341 | UIKit.framework/Headers/UIWindow.h 342 | 343 | 344 | 345 | 346 | 0 347 | IBCocoaTouchFramework 348 | 349 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 350 | 351 | 352 | 353 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 354 | 355 | 356 | YES 357 | Leaves.xcodeproj 358 | 3 359 | 87 360 | 361 | 362 | -------------------------------------------------------------------------------- /LeavesExamples/Resources/kitten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/leaves/7f2fd7b5796efc5e46d3ac7a6e28edeea0440dc7/LeavesExamples/Resources/kitten.jpg -------------------------------------------------------------------------------- /LeavesExamples/Resources/kitten2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/leaves/7f2fd7b5796efc5e46d3ac7a6e28edeea0440dc7/LeavesExamples/Resources/kitten2.jpg -------------------------------------------------------------------------------- /LeavesExamples/Resources/kitten3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/leaves/7f2fd7b5796efc5e46d3ac7a6e28edeea0440dc7/LeavesExamples/Resources/kitten3.jpg -------------------------------------------------------------------------------- /LeavesExamples/Resources/paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brow/leaves/7f2fd7b5796efc5e46d3ac7a6e28edeea0440dc7/LeavesExamples/Resources/paper.pdf -------------------------------------------------------------------------------- /LeavesExamples/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LeavesExamples 4 | // 5 | // Created by Tom Brow on 4/18/10. 6 | // Copyright Tom Brow 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | #Leaves 2 | 3 | Leaves is an animated interface for navigating through a sequence of images 4 | using page-turning gestures. As of iOS 5, Leaves is mostly obsoleted by 5 | [UIPageViewController]. 6 | 7 | Leaves requires iOS 3.0 or later. 8 | 9 | ##Installation 10 | 11 | 1. Add the files in the `Leaves` subdirectory to your Xcode project. 12 | 2. Ensure that your target links against `QuartzCore.framework`. 13 | 14 | ##Usage 15 | 16 | Creating a page-turning view controller is as simple as subclassing 17 | [LeavesViewController][]: 18 | 19 | #import "LeavesViewController.h" 20 | 21 | @interface ColorSwatchViewController : LeavesViewController 22 | @end 23 | 24 | ...and implementing the [LeavesViewDataSource][LeavesView] protocol: 25 | 26 | @implementation ColorSwatchViewController 27 | 28 | - (NSUInteger)numberOfPagesInLeavesView:(LeavesView*)leavesView { 29 | return 10; 30 | } 31 | 32 | - (void)renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)context { 33 | CGContextSetFillColorWithColor( 34 | context, 35 | [[UIColor colorWithHue:index/10.0 36 | saturation:0.8 37 | brightness:0.8 38 | alpha:1.0] CGColor]); 39 | CGContextFillRect(ctx, CGContextGetClipBoundingBox(ctx)); 40 | } 41 | 42 | @end 43 | 44 | You may also use [LeavesView] directly. For more examples, see the included 45 | `LeavesExamples` project. 46 | 47 | ##Forks 48 | * [Two-page view](https://github.com/ole/leaves/tree/twopages) by [ole](https://github.com/ole) ([blog post](http://oleb.net/blog/2010/06/app-store-safe-page-curl-animations/)) 49 | * [Zooming](https://github.com/hammerlyrodrigo/leaves) by [hammerlyrodrigo](https://github.com/hammerlyrodrigo) 50 | * [ARC](https://github.com/tjboudreaux/leaves) by [tjboudreaux](https://github.com/tjboudreaux) 51 | * [Retina support](https://github.com/Vortec4800/leaves) by [Vortec4800](https://github.com/Vortec4800) 52 | 53 | ## Articles 54 | * [App Store-safe Page Curl animations](http://oleb.net/blog/2010/06/app-store-safe-page-curl-animations/) 55 | * [How To Add A Slick iBooks Like Page Turning Effect Into Your Apps](http://maniacdev.com/2010/06/lick-ibooks-like-page-turning-effect) 56 | * [Building an iPad Reader for _War of the Worlds_](http://mobile.tutsplus.com/tutorials/iphone/building-an-ipad-reader-for-war-of-the-worlds/) 57 | 58 | [UIPageViewController]: https://developer.apple.com/library/ios/documentation/uikit/reference/UIPageViewControllerClassReferenceClassRef/UIPageViewControllerClassReference.html 59 | [LeavesViewController]: https://github.com/brow/leaves/blob/master/Leaves/LeavesViewController.h 60 | [LeavesView]: https://github.com/brow/leaves/blob/master/Leaves/LeavesView.h 61 | --------------------------------------------------------------------------------