CatNiP prefinal
Sähköinen nuottikirja, HY-TKTKL-OHTUPROJ KESÄ11
|
00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 #import "UIDocumentView.h" 00021 00022 @implementation UIDocumentView 00023 00024 @synthesize preloadFactor; 00025 @synthesize placeholder; 00026 @synthesize delegate; 00027 00035 - (void)setDocument:(UIDocument *)value 00036 { 00037 // Safely set the new value and release the old one 00038 [value retain]; 00039 [document release]; 00040 document = value; 00041 00042 // Remove all old UIImageViews 00043 for(UIView *view in container.subviews) 00044 [view removeFromSuperview]; 00045 00046 // Create new UIImageViews for the pages 00047 CGPoint pageOrigin = CGPointZero; 00048 for(int i = 1; i <= document.numberOfPages; ++i) 00049 { 00050 // Calculate the frame of the current page: horizontally centered and 00051 // vertically directly below the last one 00052 CGSize pageSize = [document getSizeOfPage:i]; 00053 pageOrigin.x = (document.size.width - pageSize.width) / 2; 00054 CGRect pageRect = CGRectMake(pageOrigin.x, pageOrigin.y, pageSize.width, pageSize.height); 00055 pageOrigin.y += pageSize.height; 00056 00057 // Create an UIImageView object for the page and add it to the container 00058 UIImageView *page = [[UIImageView alloc] initWithImage:placeholder]; 00059 page.contentMode = UIViewContentModeCenter; 00060 page.frame = pageRect; 00061 [container addSubview:page]; 00062 [page release]; 00063 } 00064 00065 // Back up zoom scale range 00066 float minimumZoomScale = self.minimumZoomScale; 00067 self.minimumZoomScale = 1.0; 00068 00069 float maximumZoomScale = self.maximumZoomScale; 00070 self.maximumZoomScale = 1.0; 00071 00072 // Reset zoom and offset for a clean container resizing experience 00073 self.zoomScale = 1.0; 00074 self.contentOffset = CGPointZero; 00075 00076 container.frame = CGRectMake(0, 0, document.size.width, document.size.height); 00077 self.contentSize = container.frame.size; 00078 00079 // Restore zoom scale range 00080 self.minimumZoomScale = minimumZoomScale; 00081 self.maximumZoomScale = maximumZoomScale; 00082 00083 // Set zoom scale as close to fit-to-width as possible, reset content 00084 // offset for good measure 00085 self.zoomScale = self.bounds.size.width / self.document.size.width; 00086 self.contentOffset = CGPointZero; 00087 } 00088 00093 - (UIDocument *)document 00094 { 00095 return document; 00096 } 00097 00106 - (id)init 00107 { 00108 placeholder = nil; 00109 preloadFactor = 0.0; 00110 container = [[UIView alloc] init]; 00111 operationQueue = [[NSOperationQueue alloc] init]; 00112 // Fast deceleration is best 00113 [self setDecelerationRate:UIScrollViewDecelerationRateFast]; 00114 [self addSubview:container]; 00115 [super setDelegate:self]; 00116 return self; 00117 } 00118 00124 - (id)initWithDocument:(UIDocument *)uiDocument 00125 { 00126 if((self = [super init])) { 00127 self = [self init]; 00128 self.document = uiDocument; 00129 } 00130 return self; 00131 } 00132 00141 - (id)initWithCoder:(NSCoder *)aDecoder 00142 { 00143 if((self = [super initWithCoder:aDecoder])) 00144 return [self init]; 00145 else 00146 return nil; 00147 } 00148 00155 - (id)initWithFrame:(CGRect)frame 00156 { 00157 if((self = [super initWithFrame:frame])) 00158 return [self init]; 00159 else 00160 return nil; 00161 } 00162 00166 - (void)refresh 00167 { 00168 // Cancel all operations so we don't accidentally load the same page twice 00169 // (this happens anyway at times thanks to parallelism, but this makes it 00170 // less bad.) 00171 [operationQueue cancelAllOperations]; 00172 00173 // Calculate the area the pages intersecting with which are loaded into 00174 // memory 00175 CGRect cacheView = CGRectMake( 00176 (self.contentOffset.x - self.bounds.size.width * preloadFactor) / self.zoomScale, 00177 (self.contentOffset.y - self.bounds.size.height * preloadFactor) / self.zoomScale, 00178 (self.bounds.size.width * (2 * preloadFactor + 1)) / self.zoomScale, 00179 (self.bounds.size.height * (2 * preloadFactor + 1)) / self.zoomScale 00180 ); 00181 CGPoint pageOrigin = CGPointZero; 00182 00183 // Loop through the document's pages 00184 for(int i = 1; i <= document.numberOfPages; ++i) { 00185 // Calculate the frame of the page: horizontally centered and vertically 00186 // directly below the last one 00187 CGSize pageSize = [document getSizeOfPage:i]; 00188 pageOrigin.x = (document.size.width - pageSize.width) / 2; 00189 00190 UIImageView *page = [container.subviews objectAtIndex:i - 1]; 00191 CGRect pageRect = CGRectMake(pageOrigin.x, pageOrigin.y, pageSize.width, pageSize.height); 00192 00193 // Check if the frame of the page intersects with the area to be loaded 00194 // into memory 00195 if(CGRectIntersectsRect(cacheView, pageRect)) { 00196 // Make sure the page image hasn't been loaded already; 00197 // if it hasn't, add a load operation to the queue 00198 if(page.image == placeholder) { 00199 // Make sure the page image STILL hasn't been loaded into// memory while this operation was sitting in the queue// Load an image into memory and set it as the// page-UIImageView's new image; the setting has to be// done on the main thread so that the OS doesn't// decide to delay it[operationQueue addOperationWithBlock:^{ 00200 00201 00202 if(page.image == placeholder) { 00203 00204 00205 00206 00207 UIImage *image = [document getImageOfPage:i]; 00208 [page performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; 00209 } 00210 }]; 00211 } 00212 } 00213 else { 00214 // If the image hasn't been unloaded, do it now. Kind of a 00215 // redundant check, but it's in place for debugging reasons. 00216 if(page.image != placeholder) { 00217 page.image = placeholder; 00218 } 00219 } 00220 00221 // Increment the y coordinate of the origin so that the frame of the 00222 // next page is calculated correctly 00223 pageOrigin.y += pageSize.height; 00224 } 00225 } 00226 00229 - (void)centerContent 00230 { 00231 // Using container.center didn't work for whatever reason, so this had to 00232 // be done by manually manipulating its frame. 00233 00234 CGFloat x = 0.0; 00235 if(self.contentSize.width < self.bounds.size.width) 00236 x = (self.bounds.size.width - self.contentSize.width) / 2; 00237 00238 CGFloat y = 0.0; 00239 if(self.contentSize.height < self.bounds.size.height) 00240 y = (self.bounds.size.height - self.contentSize.height) / 2; 00241 00242 container.frame = CGRectMake(x, y, container.frame.size.width, container.frame.size.height); 00243 } 00244 00245 #pragma mark - UIScrollViewDelegate methods for zooming and lazy load. 00246 // These methods are mostly here just to conform to the UIScrollViewDelegate 00247 // protocol and to make the overridden delegate property work properly 00248 00249 - (void)scrollViewDidScroll:(UIScrollView *)scrollView 00250 { 00251 [self refresh]; 00252 00253 if([delegate respondsToSelector:@selector(scrollViewDidScroll:)]) 00254 [delegate scrollViewDidScroll:scrollView]; 00255 } 00256 00257 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView 00258 { 00259 if([delegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) 00260 return [delegate viewForZoomingInScrollView:scrollView]; 00261 // Zooming only applies to one view object, so it needs to be the container 00262 return container; 00263 } 00264 00265 - (void)scrollViewDidZoom:(UIScrollView *)scrollView 00266 { 00267 [self centerContent]; 00268 00269 if([delegate respondsToSelector:@selector(scrollViewDidZoom:)]) 00270 [delegate scrollViewDidZoom:scrollView]; 00271 } 00272 00273 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 00274 { 00275 if([delegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) 00276 [delegate scrollViewWillBeginDragging:scrollView]; 00277 } 00278 00279 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 00280 { 00281 if([delegate respondsToSelector:@selector(scrollViewWillEndDragging:)]) 00282 [delegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; 00283 } 00284 00285 - (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView 00286 { 00287 if([delegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) 00288 return [delegate scrollViewShouldScrollToTop:scrollView]; 00289 return YES; 00290 } 00291 00292 - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView 00293 { 00294 if([delegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) 00295 [delegate scrollViewDidScrollToTop:scrollView]; 00296 } 00297 00298 - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView 00299 { 00300 if([delegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) 00301 [delegate scrollViewWillBeginDecelerating:scrollView]; 00302 } 00303 00304 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 00305 { 00306 if([delegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) 00307 [delegate scrollViewDidEndDecelerating:scrollView]; 00308 } 00309 00310 - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view 00311 { 00312 if([delegate respondsToSelector:@selector(scrollViewWillBeginZooming:)]) 00313 [delegate scrollViewWillBeginZooming:scrollView withView:view]; 00314 } 00315 00316 - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale 00317 { 00318 if([delegate respondsToSelector:@selector(scrollViewDidEndZooming:)]) 00319 [delegate scrollViewDidEndZooming:scrollView withView:view atScale:scale]; 00320 } 00321 00322 - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView 00323 { 00324 if([delegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) 00325 [delegate scrollViewDidEndScrollingAnimation:scrollView]; 00326 } 00327 00328 - (void)dealloc 00329 { 00330 [placeholder release]; 00331 [container release]; 00332 [document release]; 00333 [super dealloc]; 00334 } 00335 00336 @end