使用 UIScrollView 和 PageControl 定义滚动量
对于我正在开发的应用程序,我需要一个带有分页的滚动视图以及许多视图(在本例中为表视图)。设置它(使用 Apple 的 PageControl 示例)非常简单,并且我可以毫无问题地使其在页面之间滚动和对齐。我希望表格视图几乎像滚动视图中表格视图的缩略图表示一样。一旦您单击其中一个,它就会打开或放大以使表格视图覆盖整个屏幕。再说一遍,设置这个并不是真正的问题,我可以将滚动视图内的视图设置为我想要的任何大小,并且单击我确信当我到达该部分时我可以开始工作。 :)
我的问题是这样的:在任何给定的视图中,无论您恰好在哪个页面上,我都希望下一页和上一页分别在右侧和左侧稍微可见。当然,在第一页上,右侧只会再显示一个页面,或者最后一页会在左侧显示。同样,通过设置显示的视图(表视图)的 x 原点,我可以使第一页看起来正确。然而,一旦滚动,问题就变得明显,即屏幕滚动得太远。
分解它我想我的主要问题是我似乎无法更改切换页面时完成的滚动量。
如果我能得到任何帮助,我将不胜感激,谢谢。
AppDelegate.h
#import <UIKit/UIKit.h>
@interface AppDelegate : NSObject <UIApplicationDelegate, UIScrollViewDelegate> {
UIWindow *window;
UIView *background;
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
// To be used when scrolls originate from the UIPageControl
// I've commented this out (and all references to it) since I've disabled user interaction with the UIPageControl
//BOOL pageControlUsed;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UIView *background;
@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
@property (nonatomic, retain) NSMutableArray *viewControllers;
- (IBAction)changePage:(id)sender;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "MyViewController.h"
static NSUInteger kNumberOfPages = 4;
@interface AppDelegate (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
@end
@implementation AppDelegate
@synthesize window, scrollView, pageControl, viewControllers, background;
- (void)dealloc {
[background release];
[viewControllers release];
[scrollView release];
[pageControl release];
[window release];
[super dealloc];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
background.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Background.png"]];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= kNumberOfPages) return;
// replace the placeholder if necessary
MyViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[MyViewController alloc] initWithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (nil == controller.view.superview) {
CGRect frame = CGRectMake(50, 50, 220, 330);
frame.origin.x = 50 + (250 * page);
frame.origin.y = 50;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
/*if (pageControlUsed) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}*/
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
//pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
//pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
//pageControlUsed = YES;
}
@end
For the application I am working on I need a scrollview with paging along with a number of views (in this case tableviews). Setting this up (using Apple's PageControl example) is easy enough and I have no problem making it work in regards to scrolling and snapping between pages. I want the tableviews to be almost like thumbnail representations of the tableviews in the scrollview. Once you click one it opens or zooms in to let the tableview cover the entire screen. Again, setting this up is not really a problem, I can make the views inside the scrollview any size I want and the clicking I'm sure I can get to work when I get to that part. :)
My Problem is this: In any given view, regardless of what page you happen to be on I want the next page and the previous page to be slightly visible on the right and left side respectively. Of course on the first page there would only be one more page shown on the right side, or left side for the last page. Again, by setting the x-origin of the views (tableviews) shown I can get the first page to look right. However, as soon as you scroll the problem becomes apparent, namely that the screen scrolls too far.
Breaking it down I guess my main issue is that I can't seem to change the amount of scrolling done when switching pages.
I'd appreciate any help I can get on this, thank you.
AppDelegate.h
#import <UIKit/UIKit.h>
@interface AppDelegate : NSObject <UIApplicationDelegate, UIScrollViewDelegate> {
UIWindow *window;
UIView *background;
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
// To be used when scrolls originate from the UIPageControl
// I've commented this out (and all references to it) since I've disabled user interaction with the UIPageControl
//BOOL pageControlUsed;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UIView *background;
@property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
@property (nonatomic, retain) NSMutableArray *viewControllers;
- (IBAction)changePage:(id)sender;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "MyViewController.h"
static NSUInteger kNumberOfPages = 4;
@interface AppDelegate (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
@end
@implementation AppDelegate
@synthesize window, scrollView, pageControl, viewControllers, background;
- (void)dealloc {
[background release];
[viewControllers release];
[scrollView release];
[pageControl release];
[window release];
[super dealloc];
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
background.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Background.png"]];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= kNumberOfPages) return;
// replace the placeholder if necessary
MyViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[MyViewController alloc] initWithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (nil == controller.view.superview) {
CGRect frame = CGRectMake(50, 50, 220, 330);
frame.origin.x = 50 + (250 * page);
frame.origin.y = 50;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
/*if (pageControlUsed) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}*/
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
//pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
//pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
//pageControlUsed = YES;
}
@end
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看来您对
scrollView
的框架大小和controller.view
的框架设置不同。 scrollView 是一个 IBOutlet,这意味着您正在使用界面生成器创建scrollView,但您正在使用以下行放置内容:并将其放入scrollView 中。如果您不想在滚动视图一侧看到上一页/下一页,则必须更改第一行使用的数字。尝试使用“scrollView.frame.size”或检查从 IB 创建的滚动视图的帧大小,并使用它们而不是幻数,这是您应该避免的。
It seems that you are setting the frame size of the
scrollView
and the frame ofcontroller.view
differently. The scrollView is an IBOutlet, that means that you are creating the scrollView usign the interface builder, but you are putting content using this lines:and putting it into the scrollView. If you do not want to see the previous/next page on the side of your scrollView, you have to change the numbers you are using at the first line. Try using `scrollView.frame.size or check the frame size of the scrollView you created from the IB and use them instead of magic numbers, which you should avoid.