Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Moved most of the logic into a UIScrollView subclass, which is a neat…

…er solution. It works like UITableView, with a delegate that provides the number of pages and the actual views for the pages.
  • Loading branch information...
commit 500e0638aabb626b0c94e99fa7258131f9253106 1 parent 3f25630
@hollance authored
View
12 Paging.xcodeproj/project.pbxproj
@@ -24,7 +24,7 @@
7B5F044D136302F3006782F8 /* AppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F043E136302F3006782F8 /* AppViewController.m */; };
7B5F044E136302F3006782F8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F043F136302F3006782F8 /* main.m */; };
7B94AC4C136BF9900079ECCB /* PageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B94AC4B136BF9900079ECCB /* PageView.m */; };
- 7B94AC50136C035A0079ECCB /* MHPreviewScrollViewContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B94AC4F136C035A0079ECCB /* MHPreviewScrollViewContainer.m */; };
+ 7BC2ED65136C3A4100A9D610 /* MHPagingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BC2ED64136C3A4100A9D610 /* MHPagingScrollView.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -51,8 +51,8 @@
7B5F0440136302F3006782F8 /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
7B94AC4A136BF9900079ECCB /* PageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageView.h; sourceTree = "<group>"; };
7B94AC4B136BF9900079ECCB /* PageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageView.m; sourceTree = "<group>"; };
- 7B94AC4E136C035A0079ECCB /* MHPreviewScrollViewContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MHPreviewScrollViewContainer.h; sourceTree = "<group>"; };
- 7B94AC4F136C035A0079ECCB /* MHPreviewScrollViewContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MHPreviewScrollViewContainer.m; sourceTree = "<group>"; };
+ 7BC2ED63136C3A4100A9D610 /* MHPagingScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; path = MHPagingScrollView.h; sourceTree = "<group>"; };
+ 7BC2ED64136C3A4100A9D610 /* MHPagingScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MHPagingScrollView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -134,8 +134,8 @@
7B5F0440136302F3006782F8 /* Prefix.pch */,
7B94AC4A136BF9900079ECCB /* PageView.h */,
7B94AC4B136BF9900079ECCB /* PageView.m */,
- 7B94AC4E136C035A0079ECCB /* MHPreviewScrollViewContainer.h */,
- 7B94AC4F136C035A0079ECCB /* MHPreviewScrollViewContainer.m */,
+ 7BC2ED63136C3A4100A9D610 /* MHPagingScrollView.h */,
+ 7BC2ED64136C3A4100A9D610 /* MHPagingScrollView.m */,
);
path = Sources;
sourceTree = "<group>";
@@ -214,7 +214,7 @@
7B5F044D136302F3006782F8 /* AppViewController.m in Sources */,
7B5F044E136302F3006782F8 /* main.m in Sources */,
7B94AC4C136BF9900079ECCB /* PageView.m in Sources */,
- 7B94AC50136C035A0079ECCB /* MHPreviewScrollViewContainer.m in Sources */,
+ 7BC2ED65136C3A4100A9D610 /* MHPagingScrollView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
19 README.txt
@@ -3,20 +3,5 @@ without the CATiledLayer pinch-to-zoom stuff.
I added the ability to see previews of the pages on the left and right.
-It might be cool to refactor this as follows:
- - Put most of the logic into a PagingScrollView class, that is a subclass
- of UIScrollView.
- - The hitTest logic that is now in MHPreviewScrollViewContainer can go
- into PagingScrollView as well, making this class unnecessary. See:
- http://stackoverflow.com/questions/1677085/paging-uiscrollview-in-increments-smaller-than-content-size
- - PagingScrollView is its own UIScrollViewDelegate OR you need to call its
- scrollViewDidScroll directly.
- - PagingScrollView needs to handle auto-rotation methods. Are there
- notifications for all of them, or does the VC need to forward them?
- - There is a PagingScrollViewDelegate that does the dequeue. PageView is
- now unknown to PagingScrollView.
- - We now no longer store pageIndex in PageView, but need some other way
- of making this connection (probably by storing another type in the set
- that maps the visible views to indexes)
- - AppViewController does page control thing, implements the delegate,
- creates PageViews
+I moved most of the logic into a UIScrollView subclass that uses a delegate
+much in the way UITableView uses a data source.
View
46 Resources/MainWindow.xib
@@ -57,7 +57,7 @@
<string key="NSFrame">{{0, 424}, {320, 36}}</string>
<reference key="NSSuperview" ref="361271949"/>
<reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="108078305"/>
+ <reference key="NSNextKeyView"/>
<bool key="IBUIOpaque">NO</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<int key="IBUIContentHorizontalAlignment">0</int>
@@ -91,6 +91,7 @@
<string key="NSFrameSize">{320, 416}</string>
<reference key="NSSuperview" ref="361271949"/>
<reference key="NSWindow"/>
+ <reference key="NSNextKeyView" ref="663150079"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MC4yNTA5ODAzOTIyIDAuMjUwOTgwMzkyMiAwLjI1MDk4MDM5MjIAA</bytes>
@@ -101,7 +102,7 @@
<string key="NSFrame">{{0, 20}, {320, 460}}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
- <reference key="NSNextKeyView" ref="663150079"/>
+ <reference key="NSNextKeyView" ref="108078305"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
@@ -122,6 +123,7 @@
<string key="NSFrameSize">{320, 480}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
+ <reference key="NSNextKeyView"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MSAxIDEAA</bytes>
@@ -187,19 +189,19 @@
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
- <string key="label">scrollView</string>
- <reference key="source" ref="108078305"/>
+ <string key="label">pagingScrollView</string>
+ <reference key="source" ref="943309135"/>
<reference key="destination" ref="663150079"/>
</object>
- <int key="connectionID">24</int>
+ <int key="connectionID">25</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
- <string key="label">pagingScrollView</string>
- <reference key="source" ref="943309135"/>
- <reference key="destination" ref="663150079"/>
+ <string key="label">pagingDelegate</string>
+ <reference key="source" ref="663150079"/>
+ <reference key="destination" ref="943309135"/>
</object>
- <int key="connectionID">25</int>
+ <int key="connectionID">26</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
@@ -286,8 +288,8 @@
<string>12.IBPluginDependency</string>
<string>16.IBPluginDependency</string>
<string>17.IBPluginDependency</string>
+ <string>18.CustomClassName</string>
<string>18.IBPluginDependency</string>
- <string>23.CustomClassName</string>
<string>23.IBPluginDependency</string>
<string>3.CustomClassName</string>
<string>3.IBPluginDependency</string>
@@ -303,8 +305,8 @@
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+ <string>MHPagingScrollView</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
- <string>MHPreviewScrollViewContainer</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>AppDelegate</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
@@ -322,7 +324,7 @@
<reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
- <int key="maxID">25</int>
+ <int key="maxID">26</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -391,7 +393,7 @@
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>UIPageControl</string>
- <string>UIScrollView</string>
+ <string>PagingScrollView</string>
</object>
</object>
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
@@ -409,7 +411,7 @@
</object>
<object class="IBToOneOutletInfo">
<string key="name">pagingScrollView</string>
- <string key="candidateClassName">UIScrollView</string>
+ <string key="candidateClassName">PagingScrollView</string>
</object>
</object>
</object>
@@ -419,22 +421,22 @@
</object>
</object>
<object class="IBPartialClassDescription">
- <string key="className">MHPreviewScrollViewContainer</string>
- <string key="superclassName">UIView</string>
+ <string key="className">MHPagingScrollView</string>
+ <string key="superclassName">UIScrollView</string>
<object class="NSMutableDictionary" key="outlets">
- <string key="NS.key.0">scrollView</string>
- <string key="NS.object.0">UIScrollView</string>
+ <string key="NS.key.0">pagingDelegate</string>
+ <string key="NS.object.0">id</string>
</object>
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
- <string key="NS.key.0">scrollView</string>
+ <string key="NS.key.0">pagingDelegate</string>
<object class="IBToOneOutletInfo" key="NS.object.0">
- <string key="name">scrollView</string>
- <string key="candidateClassName">UIScrollView</string>
+ <string key="name">pagingDelegate</string>
+ <string key="candidateClassName">id</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
- <string key="minorKey">./Classes/MHPreviewScrollViewContainer.h</string>
+ <string key="minorKey">./Classes/MHPagingScrollView.h</string>
</object>
</object>
</object>
View
14 Sources/AppViewController.h
@@ -1,20 +1,14 @@
-@interface AppViewController : UIViewController <UIScrollViewDelegate>
+#import "MHPagingScrollView.h"
+
+@interface AppViewController : UIViewController <MHPagingScrollViewDelegate, UIScrollViewDelegate>
{
int numPages;
- NSMutableSet* recycledPages;
- NSMutableSet* visiblePages;
- CGFloat previewWidth;
-
- int firstVisiblePageIndexBeforeRotation; // for autorotation
- CGFloat percentScrolledIntoFirstVisiblePage;
}
-@property (nonatomic, retain) IBOutlet UIScrollView* pagingScrollView;
+@property (nonatomic, retain) IBOutlet MHPagingScrollView* pagingScrollView;
@property (nonatomic, retain) IBOutlet UIPageControl* pageControl;
- (IBAction)pageTurn;
-- (void)reloadPages;
-
@end
View
171 Sources/AppViewController.m
@@ -10,22 +10,17 @@ - (void)viewDidLoad
{
[super viewDidLoad];
- recycledPages = [[NSMutableSet alloc] init];
- visiblePages = [[NSMutableSet alloc] init];
-
- pagingScrollView.contentOffset = CGPointZero;
- pageControl.currentPage = 0;
-
- previewWidth = 50.0f;
numPages = 2;
- [self reloadPages];
+ pagingScrollView.previewInsets = UIEdgeInsetsMake(0, 50, 0, 50);
+ [pagingScrollView reloadPages];
+
+ pageControl.currentPage = 0;
+ pageControl.numberOfPages = numPages;
}
- (void)releaseObjects
{
- [recycledPages release], recycledPages = nil;
- [visiblePages release], visiblePages = nil;
[pagingScrollView release], pagingScrollView = nil;
[pageControl release], pageControl = nil;
}
@@ -42,114 +37,17 @@ - (void)dealloc
[super dealloc];
}
-#pragma mark -
-#pragma mark Actions
-
-- (IBAction)pageTurn
+- (void)didReceiveMemoryWarning
{
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:0.3f];
- [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
-
- CGFloat width = pagingScrollView.bounds.size.width;
- pagingScrollView.contentOffset = CGPointMake(width * pageControl.currentPage, 0);
-
- [UIView commitAnimations];
+ [pagingScrollView didReceiveMemoryWarning];
}
#pragma mark -
-#pragma mark Page Recycling and Configuration
-
-- (CGSize)contentSizeForPagingScrollView
-{
- CGRect rect = pagingScrollView.bounds;
- return CGSizeMake(rect.size.width * numPages, rect.size.height);
-}
-
-- (int)indexOfCurrentPage
-{
- CGFloat width = pagingScrollView.bounds.size.width;
- int currentPage = (pagingScrollView.contentOffset.x + width/2.0f) / width;
- return currentPage;
-}
-
-- (BOOL)isDisplayingPageForIndex:(NSUInteger)index
-{
- for (PageView* page in visiblePages)
- {
- if (page.pageIndex == index)
- return YES;
- }
- return NO;
-}
-
-- (PageView*)dequeueRecycledPage
-{
- PageView* page = [recycledPages anyObject];
- if (page != nil)
- {
- [[page retain] autorelease];
- [recycledPages removeObject:page];
- }
- return page;
-}
-
-- (CGRect)frameForPageAtIndex:(NSUInteger)index
-{
- CGRect rect = pagingScrollView.bounds;
- rect.origin.x = rect.size.width * index;
- return rect;
-}
-
-- (void)configurePage:(PageView*)page forIndex:(NSUInteger)index
-{
- page.pageIndex = index;
- page.frame = [self frameForPageAtIndex:index];
-}
-
-- (void)tilePages
-{
- CGRect visibleBounds = pagingScrollView.bounds;
- CGFloat pageWidth = CGRectGetWidth(visibleBounds);
- visibleBounds.origin.x -= previewWidth;
- visibleBounds.size.width += previewWidth*2;
-
- int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / pageWidth);
- int lastNeededPageIndex = floorf((CGRectGetMaxX(visibleBounds)-1) / pageWidth);
- firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
- lastNeededPageIndex = MIN(lastNeededPageIndex, numPages - 1);
-
- for (PageView* page in visiblePages)
- {
- if (page.pageIndex < firstNeededPageIndex || page.pageIndex > lastNeededPageIndex)
- {
- [recycledPages addObject:page];
- [page removeFromSuperview];
- }
- }
-
- [visiblePages minusSet:recycledPages];
-
- for (int i = firstNeededPageIndex; i <= lastNeededPageIndex; ++i)
- {
- if (![self isDisplayingPageForIndex:i])
- {
- PageView* page = [self dequeueRecycledPage];
- if (page == nil)
- page = [[[PageView alloc] init] autorelease];
-
- [self configurePage:page forIndex:i];
- [pagingScrollView addSubview:page];
- [visiblePages addObject:page];
- }
- }
-}
+#pragma mark Actions
-- (void)reloadPages
+- (IBAction)pageTurn
{
- pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
- pageControl.numberOfPages = numPages;
- [self tilePages];
+ [pagingScrollView selectPageAtIndex:pageControl.currentPage animated:YES];
}
#pragma mark -
@@ -162,29 +60,12 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfa
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
- CGFloat offset = pagingScrollView.contentOffset.x;
- CGFloat pageWidth = pagingScrollView.bounds.size.width;
-
- if (offset >= 0)
- firstVisiblePageIndexBeforeRotation = floorf(offset / pageWidth);
- else
- firstVisiblePageIndexBeforeRotation = 0;
-
- percentScrolledIntoFirstVisiblePage = offset / pageWidth - firstVisiblePageIndexBeforeRotation;
+ [pagingScrollView beforeRotation];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
- pagingScrollView.contentSize = [self contentSizeForPagingScrollView];
-
- for (PageView* page in visiblePages)
- {
- page.frame = [self frameForPageAtIndex:page.pageIndex];
- }
-
- CGFloat pageWidth = pagingScrollView.bounds.size.width;
- CGFloat newOffset = (firstVisiblePageIndexBeforeRotation + percentScrolledIntoFirstVisiblePage) * pageWidth;
- pagingScrollView.contentOffset = CGPointMake(newOffset, 0);
+ [pagingScrollView afterRotation];
}
#pragma mark -
@@ -192,18 +73,36 @@ - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInte
- (void)scrollViewDidScroll:(UIScrollView*)theScrollView
{
- pageControl.currentPage = [self indexOfCurrentPage];
- [self tilePages];
+ pageControl.currentPage = [pagingScrollView indexOfSelectedPage];
+ [pagingScrollView scrollViewDidScroll];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView*)theScrollView
{
- int currentPage = [self indexOfCurrentPage];
- if (currentPage == numPages - 1)
+ if ([pagingScrollView indexOfSelectedPage] == numPages - 1)
{
numPages++;
- [self reloadPages];
+ [pagingScrollView reloadPages];
+ pageControl.numberOfPages = numPages;
}
}
+#pragma mark -
+#pragma mark MHPagingScrollViewDelegate
+
+- (NSInteger)numberOfPagesInPagingScrollView:(MHPagingScrollView*)pagingScrollView
+{
+ return numPages;
+}
+
+- (UIView*)pagingScrollView:(MHPagingScrollView*)thePagingScrollView pageForIndex:(NSInteger)index
+{
+ PageView* pageView = (PageView*)[thePagingScrollView dequeueReusablePage];
+ if (pageView == nil)
+ pageView = [[[PageView alloc] init] autorelease];
+
+ [pageView setPageIndex:index];
+ return pageView;
+}
+
@end
View
132 Sources/MHPagingScrollView.h
@@ -0,0 +1,132 @@
+/*
+ Based on the PhotoScroller sample code.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
+ Inc. ("Apple") in consideration of your agreement to the following
+ terms, and your use, installation, modification or redistribution of
+ this Apple software constitutes acceptance of these terms. If you do
+ not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and
+ subject to these terms, Apple grants you a personal, non-exclusive
+ license, under Apple's copyrights in this original Apple software (the
+ "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ Software, with or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in its entirety and
+ without modifications, you must retain this notice and the following
+ text and disclaimers in all such redistributions of the Apple Software.
+ Neither the name, trademarks, service marks or logos of Apple Inc. may
+ be used to endorse or promote products derived from the Apple Software
+ without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or
+ implied, are granted by Apple herein, including but not limited to any
+ patent rights that may be infringed by your derivative works or by other
+ works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
+ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ Copyright (C) 2010 Apple Inc. All Rights Reserved.
+
+ */
+
+@class MHPagingScrollView;
+
+/*!
+ * Delegate protocol for MHPagingScrollView.
+ */
+@protocol MHPagingScrollViewDelegate <NSObject>
+
+/*!
+ * Asks the delegate to return the number of pages.
+ */
+- (NSInteger)numberOfPagesInPagingScrollView:(MHPagingScrollView*)pagingScrollView;
+
+/*!
+ * Asks the delegate for a page to insert. The delegate should ask for a
+ * reusable view using dequeueReusablePageView.
+ */
+- (UIView*)pagingScrollView:(MHPagingScrollView*)pagingScrollView pageForIndex:(NSInteger)index;
+
+@end
+
+/*!
+ * A paging scroll view that uses a reusable page mechanism like UITableView.
+ *
+ * MHPagingScrollView allows you to show partial previews of the pages to the
+ * left and right of the current page. The bounds of the scroll view always
+ * correspond to a single page. To allow these previews, make the scroll view
+ * smaller to make room for the preview pages and set the previewInsets
+ * property.
+ */
+@interface MHPagingScrollView : UIScrollView
+{
+ NSMutableSet* recycledPages;
+ NSMutableSet* visiblePages;
+
+ int firstVisiblePageIndexBeforeRotation; // for autorotation
+ CGFloat percentScrolledIntoFirstVisiblePage;
+}
+
+/*! The delegate for paging events. */
+@property (nonatomic, assign) IBOutlet id<MHPagingScrollViewDelegate> pagingDelegate;
+
+/*! The width of the preview pages. */
+@property (nonatomic, assign) UIEdgeInsets previewInsets;
+
+/*!
+ * Makes the page at the requested index visible.
+ */
+- (void)selectPageAtIndex:(NSInteger)index animated:(BOOL)animated;
+
+/*!
+ * Returns the index of the page that is currently visible.
+ */
+- (int)indexOfSelectedPage;
+
+/*!
+ * Returns a reusable UIView object.
+ */
+- (UIView*)dequeueReusablePage;
+
+/*!
+ * Reloads the pages. Call this method when the number of pages has changed.
+ */
+- (void)reloadPages;
+
+/*!
+ * Call this from your view controller's UIScrollViewDelegate.
+ */
+- (void)scrollViewDidScroll;
+
+/*!
+ * Call this from your view controller's willRotateToInterfaceOrientation if
+ * you want to support autorotation.
+ */
+- (void)beforeRotation;
+
+/*!
+ * Call this from your view controller's willAnimateRotationToInterfaceOrientation
+ * if you want to support autorotation.
+ */
+- (void)afterRotation;
+
+/*!
+ * Call this from your view controller's didReceiveMemoryWarning.
+ */
+- (void)didReceiveMemoryWarning;
+
+@end
View
267 Sources/MHPagingScrollView.m
@@ -0,0 +1,267 @@
+/*
+ Based on the PhotoScroller sample code.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
+ Inc. ("Apple") in consideration of your agreement to the following
+ terms, and your use, installation, modification or redistribution of
+ this Apple software constitutes acceptance of these terms. If you do
+ not agree with these terms, please do not use, install, modify or
+ redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and
+ subject to these terms, Apple grants you a personal, non-exclusive
+ license, under Apple's copyrights in this original Apple software (the
+ "Apple Software"), to use, reproduce, modify and redistribute the Apple
+ Software, with or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in its entirety and
+ without modifications, you must retain this notice and the following
+ text and disclaimers in all such redistributions of the Apple Software.
+ Neither the name, trademarks, service marks or logos of Apple Inc. may
+ be used to endorse or promote products derived from the Apple Software
+ without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or
+ implied, are granted by Apple herein, including but not limited to any
+ patent rights that may be infringed by your derivative works or by other
+ works in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
+ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+ Copyright (C) 2010 Apple Inc. All Rights Reserved.
+
+ */
+
+#import "MHPagingScrollView.h"
+
+@interface MHPage : NSObject
+{
+}
+
+@property (nonatomic, retain) UIView* view;
+@property (nonatomic, assign) NSInteger index;
+
+@end
+
+@implementation MHPage
+
+@synthesize view, index;
+
+- (void)dealloc
+{
+ [view release];
+ [super dealloc];
+}
+
+@end
+
+@implementation MHPagingScrollView
+
+@synthesize previewInsets, pagingDelegate;
+
+- (void)setup
+{
+ recycledPages = [[NSMutableSet alloc] init];
+ visiblePages = [[NSMutableSet alloc] init];
+
+ self.pagingEnabled = YES;
+ self.showsVerticalScrollIndicator = NO;
+ self.showsHorizontalScrollIndicator = NO;
+ self.contentOffset = CGPointZero;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame]))
+ {
+ [self setup];
+ }
+ return self;
+}
+
+- (id)initWithCoder:(NSCoder*)aDecoder
+{
+ if ((self = [super initWithCoder:aDecoder]))
+ {
+ [self setup];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [recycledPages release];
+ [visiblePages release];
+ [super dealloc];
+}
+
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
+{
+ // This allows for touch handling outside of the scroll view's bounds.
+
+ CGPoint parentLocation = [self convertPoint:point toView:self.superview];
+
+ CGRect responseRect = self.frame;
+ responseRect.origin.x -= previewInsets.left;
+ responseRect.origin.y -= previewInsets.top;
+ responseRect.size.width += (previewInsets.left + previewInsets.right);
+ responseRect.size.height += (previewInsets.top + previewInsets.bottom);
+
+ return CGRectContainsPoint(responseRect, parentLocation);
+}
+
+- (void)selectPageAtIndex:(NSInteger)index animated:(BOOL)animated
+{
+ if (animated)
+ {
+ [UIView beginAnimations:nil context:NULL];
+ [UIView setAnimationDuration:0.3f];
+ [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
+ }
+
+ self.contentOffset = CGPointMake(self.bounds.size.width * index, 0);
+
+ if (animated)
+ [UIView commitAnimations];
+}
+
+- (int)indexOfSelectedPage
+{
+ CGFloat width = self.bounds.size.width;
+ int currentPage = (self.contentOffset.x + width/2.0f) / width;
+ return currentPage;
+}
+
+- (NSInteger)numberOfPages
+{
+ return [pagingDelegate numberOfPagesInPagingScrollView:self];
+}
+
+- (CGSize)contentSizeForPagingScrollView
+{
+ CGRect rect = self.bounds;
+ return CGSizeMake(rect.size.width * [self numberOfPages], rect.size.height);
+}
+
+- (BOOL)isDisplayingPageForIndex:(NSUInteger)index
+{
+ for (MHPage* page in visiblePages)
+ {
+ if (page.index == index)
+ return YES;
+ }
+ return NO;
+}
+
+- (UIView*)dequeueReusablePage
+{
+ MHPage* page = [recycledPages anyObject];
+ if (page != nil)
+ {
+ UIView* view = [[page.view retain] autorelease];
+ [recycledPages removeObject:page];
+ return view;
+ }
+ return nil;
+}
+
+- (CGRect)frameForPageAtIndex:(NSUInteger)index
+{
+ CGRect rect = self.bounds;
+ rect.origin.x = rect.size.width * index;
+ return rect;
+}
+
+- (void)tilePages
+{
+ CGRect visibleBounds = self.bounds;
+ CGFloat pageWidth = CGRectGetWidth(visibleBounds);
+ visibleBounds.origin.x -= previewInsets.left;
+ visibleBounds.size.width += (previewInsets.left + previewInsets.right);
+
+ int firstNeededPageIndex = floorf(CGRectGetMinX(visibleBounds) / pageWidth);
+ int lastNeededPageIndex = floorf((CGRectGetMaxX(visibleBounds)-1) / pageWidth);
+ firstNeededPageIndex = MAX(firstNeededPageIndex, 0);
+ lastNeededPageIndex = MIN(lastNeededPageIndex, [self numberOfPages] - 1);
+
+ for (MHPage* page in visiblePages)
+ {
+ if (page.index < firstNeededPageIndex || page.index > lastNeededPageIndex)
+ {
+ [recycledPages addObject:page];
+ [page.view removeFromSuperview];
+ }
+ }
+
+ [visiblePages minusSet:recycledPages];
+
+ for (int i = firstNeededPageIndex; i <= lastNeededPageIndex; ++i)
+ {
+ if (![self isDisplayingPageForIndex:i])
+ {
+ UIView* pageView = [pagingDelegate pagingScrollView:self pageForIndex:i];
+ pageView.frame = [self frameForPageAtIndex:i];
+ [self addSubview:pageView];
+
+ MHPage* page = [[MHPage alloc] init];
+ page.index = i;
+ page.view = pageView;
+ [visiblePages addObject:page];
+ [page release];
+ }
+ }
+}
+
+- (void)reloadPages
+{
+ self.contentSize = [self contentSizeForPagingScrollView];
+ [self tilePages];
+}
+
+- (void)scrollViewDidScroll
+{
+ [self tilePages];
+}
+
+- (void)beforeRotation
+{
+ CGFloat offset = self.contentOffset.x;
+ CGFloat pageWidth = self.bounds.size.width;
+
+ if (offset >= 0)
+ firstVisiblePageIndexBeforeRotation = floorf(offset / pageWidth);
+ else
+ firstVisiblePageIndexBeforeRotation = 0;
+
+ percentScrolledIntoFirstVisiblePage = offset / pageWidth - firstVisiblePageIndexBeforeRotation;
+}
+
+- (void)afterRotation
+{
+ self.contentSize = [self contentSizeForPagingScrollView];
+
+ for (MHPage* page in visiblePages)
+ page.view.frame = [self frameForPageAtIndex:page.index];
+
+ CGFloat pageWidth = self.bounds.size.width;
+ CGFloat newOffset = (firstVisiblePageIndexBeforeRotation + percentScrolledIntoFirstVisiblePage) * pageWidth;
+ self.contentOffset = CGPointMake(newOffset, 0);
+}
+
+- (void)didReceiveMemoryWarning
+{
+ [recycledPages removeAllObjects];
+}
+
+@end
View
24 Sources/MHPreviewScrollViewContainer.h
@@ -1,24 +0,0 @@
-
-/*!
- * Allows a paging UIScrollView to show previews of the pages on either side of
- * the current page.
- *
- * The size of a page in a scroll view with paging enabled is always equal to
- * the bounds of the scroll view. The current SDK does not allow you to make
- * the page size smaller. If you want to show a preview of the pages on either
- * side of the current page, you need to fake a smaller page size by making the
- * scroll view itself smaller and turning off clipping so that it draws the
- * other pages outside its bounds.
- *
- * However, the scroll view will not receive touch events on anything outside
- * its bounds. To resolve that, you have to place the scroll view on a UIView,
- * the MHPreviewScrollViewContainer, which passes on such touches to the scroll
- * view. It can also be used to draw the background behind the scroll view.
- */
-@interface MHPreviewScrollViewContainer : UIView
-{
-}
-
-@property (nonatomic, retain) IBOutlet UIScrollView* scrollView;
-
-@end
View
23 Sources/MHPreviewScrollViewContainer.m
@@ -1,23 +0,0 @@
-
-#import "MHPreviewScrollViewContainer.h"
-
-@implementation MHPreviewScrollViewContainer
-
-@synthesize scrollView;
-
-- (void)dealloc
-{
- [scrollView release];
- [super dealloc];
-}
-
-- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
-{
- UIView* child = [super hitTest:point withEvent:event];
- if (child == self)
- return self.scrollView;
- else
- return child;
-}
-
-@end
View
2  Sources/PageView.h
@@ -3,6 +3,6 @@
{
}
-@property (nonatomic, assign) NSUInteger pageIndex;
+- (void)setPageIndex:(int)newIndex;
@end
View
7 Sources/PageView.m
@@ -3,8 +3,6 @@
@implementation PageView
-@synthesize pageIndex;
-
- (id)init
{
if ((self = [super init]))
@@ -24,10 +22,9 @@ - (id)init
return self;
}
-- (void)setPageIndex:(NSUInteger)newIndex
+- (void)setPageIndex:(int)newIndex
{
- pageIndex = newIndex;
- self.text = [NSString stringWithFormat:@"%d", pageIndex];
+ self.text = [NSString stringWithFormat:@"%d", newIndex];
}
@end
Please sign in to comment.
Something went wrong with that request. Please try again.