我一直在研究如何使用UIPageControl作为应用程序的滚动部分,我想知道它是如何工作的。文档显示了更改页面,设置页面数等的方法,但页面控件本身并不包含任何类型的滚动视图。
当想要显示页面指示符时,UIPageControl和UIScrollView类是否应该结合使用(就像iPhone的主屏幕上有app页面一样)?
答案 0 :(得分:20)
我编写了一个类(PagedView),它的工作方式与UITableView类似,并以iPhone主屏幕上的方式合并UIPageControl和UIScrollView的概念。
概念基本如下:您需要实现PagedViewDelegate以返回PagedView的每个页面的页数和视图。重用视图与UITableView中的相同。使用界面构建器连接scrollview和pageControl出口。
如果您觉得这门课有用,请告诉我。
.H-文件:
//
// PagedView.h
//
// Created by Werner Altewischer on 22/10/10.
// Copyright 2010 werner-it.com. All rights reserved.
//
@protocol ReusableObject
- (NSString *)reuseIdentifier;
- (void)prepareForReuse;
@end
@class PagedView;
@protocol PagedViewDelegate
- (NSUInteger)numberOfPagesInPagedView:(PagedView *)view;
- (UIView *)pagedView:(PagedView *)view viewForPageAtIndex:(NSUInteger)page;
@end
@interface PagedView : UIView<UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
NSMutableDictionary *pageViewDictionary;
NSMutableDictionary *reuseViewDictionary;
IBOutlet id <PagedViewDelegate> delegate;
}
@property (nonatomic, assign) IBOutlet id <PagedViewDelegate> delegate;
- (UIView<ReusableObject> *)dequeueReusableViewWithIdentifier:(NSString *)identifier;
- (void)scrollToPageAtIndex:(NSUInteger)pageIndex animated:(BOOL)animated;
- (NSInteger)indexForSelectedPage;
- (CGSize)pageSize;
- (void)reloadData;
@end
的.m-文件:
//
// PagedView.m
//
// Created by Werner Altewischer on 22/10/10.
// Copyright 2010 werner-it.com. All rights reserved.
//
#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
@interface PagedView (Private)
- (NSUInteger)pageCount;
- (UIView *)loadViewForIndex:(NSUInteger)pageIndex;
- (void)unloadViewForIndex:(NSUInteger)pageIndex;
- (void)loadViewsForVisiblePages:(BOOL)reloadData;
- (UIView *)viewForIndex:(NSUInteger)pageIndex;
@end
@implementation PagedView
@synthesize delegate;
- (void)dealloc {
TT_RELEASE_SAFELY(pageViewDictionary);
TT_RELEASE_SAFELY(reuseViewDictionary);
TT_RELEASE_SAFELY(scrollView);
TT_RELEASE_SAFELY(pageControl);
[super dealloc];
}
- (CGSize)pageSize {
return scrollView.frame.size;
}
- (void)reloadData {
if (!pageViewDictionary) {
//First time initialization
pageViewDictionary = [NSMutableDictionary new];
reuseViewDictionary = [NSMutableDictionary new];
[pageControl addTarget:self action:@selector(pageChanged:) forControlEvents:UIControlEventValueChanged];
scrollView.delegate = self;
scrollView.pagingEnabled = YES;
}
CGSize size = self.pageSize;
NSUInteger numberOfPages = self.pageCount;
pageControl.numberOfPages = MAX(1, numberOfPages);
[scrollView setContentSize:CGSizeMake(size.width * numberOfPages, size.height)];
pageControl.currentPage = self.indexForSelectedPage;
pageControl.hidden = (numberOfPages == 0);
[self loadViewsForVisiblePages:YES];
}
- (void)layoutSubviews {
if (!pageViewDictionary) {
[self reloadData];
}
}
- (void)scrollToPageAtIndex:(NSUInteger)pageIndex animated:(BOOL)animated {
if (pageIndex < self.pageCount) {
CGSize size = scrollView.frame.size;
CGRect rect = CGRectMake(size.width * pageIndex, 0, size.width, size.height);
[scrollView scrollRectToVisible:rect animated:animated];
}
}
- (NSInteger)indexForSelectedPage {
CGFloat cx = scrollView.contentOffset.x;
NSUInteger index = (NSUInteger)(cx / scrollView.frame.size.width);
if (index >= self.pageCount) {
index = NSNotFound;
}
return index;
}
#pragma mark -
#pragma mark UIScrollViewDelegate implementation
- (void)scrollViewWillBeginDragging:(UIScrollView *)theScrollView {
theScrollView.userInteractionEnabled = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)theScrollView {
if (theScrollView == scrollView) {
pageControl.currentPage = self.indexForSelectedPage;
[self loadViewsForVisiblePages:NO];
theScrollView.userInteractionEnabled = YES;
}
}
- (void)pageChanged:(UIPageControl *)thePageControl {
if (pageControl == thePageControl) {
[self scrollToPageAtIndex:pageControl.currentPage animated:YES];
[self loadViewsForVisiblePages:NO];
}
}
- (UIView<ReusableObject> *)dequeueReusableViewWithIdentifier:(NSString *)identifier {
UIView<ReusableObject> *v = [[[reuseViewDictionary objectForKey:identifier] retain] autorelease];
if (v) {
[v prepareForReuse];
[reuseViewDictionary removeObjectForKey:identifier];
}
return v;
}
@end
@implementation PagedView (Private)
- (NSUInteger)pageCount {
return [self.delegate numberOfPagesInPagedView:self];
}
- (UIView *)viewForIndex:(NSUInteger)pageIndex {
id key = [NSNumber numberWithUnsignedInteger:pageIndex];
return [pageViewDictionary objectForKey:key];
}
- (UIView *)loadViewForIndex:(NSUInteger)pageIndex {
id key = [NSNumber numberWithUnsignedInteger:pageIndex];
UIView *v = [pageViewDictionary objectForKey:key];
if (!v) {
CGSize size = self.pageSize;
UIView *v = [self.delegate pagedView:self viewForPageAtIndex:pageIndex];
if (v) {
v.frame = CGRectMake(pageIndex * size.width, 0, size.width, size.height);
[scrollView addSubview:v];
[pageViewDictionary setObject:v forKey:key];
}
}
return v;
}
- (void)unloadViewForIndex:(NSUInteger)pageIndex {
id key = [NSNumber numberWithUnsignedInteger:pageIndex];
UIView *v = [pageViewDictionary objectForKey:key];
if (v) {
if ([v conformsToProtocol:@protocol(ReusableObject)]) {
NSString *reuseIdentifier = [(id <ReusableObject>)v reuseIdentifier];
[reuseViewDictionary setObject:v forKey:reuseIdentifier];
}
[v removeFromSuperview];
[pageViewDictionary removeObjectForKey:key];
}
}
- (void)loadViewsForVisiblePages:(BOOL)reloadData {
//load the selected view and the one in front and behind
NSUInteger selectedPage = self.indexForSelectedPage;
NSUInteger numberOfPages = self.pageCount;
int intSelectedPage = (selectedPage == NSNotFound) ? -2 : (int)selectedPage;
//Find the max number present in the pageViewDictionary
NSUInteger existingPageCount = 0;
for (NSNumber *key in pageViewDictionary) {
if ([key unsignedIntegerValue] >= existingPageCount) {
existingPageCount = [key unsignedIntegerValue] + 1;
}
}
for (int i = 0; i < MAX(numberOfPages, existingPageCount); ++i) {
if (i >= numberOfPages ||
i < (intSelectedPage - 1) ||
i > (intSelectedPage + 1)) {
[self unloadViewForIndex:i];
} else {
if (reloadData) {
//Unload the view if we're reloading all the data
[self unloadViewForIndex:i];
}
[self loadViewForIndex:i];
}
}
[reuseViewDictionary removeAllObjects];
}
@end
答案 1 :(得分:10)
实际上,通过在UIScrollView上设置分页属性来完成分页位。页面控件只是一个有用的UI构造,但实际上并没有与分页本身做任何事情。
答案 2 :(得分:7)
UIPageControl做了两件事:(1)它显示点,包括当前所选页面的突出显示的点,以及(2)当用户点击它时,它会生成UIControlEventValueChanged事件。点击控件右侧以向右翻页;点击左侧以向左翻页。您应该实现此行为以与HIG保持一致!
要捕获事件,请添加:
[myUiPageControl addTarget:self action:@selector(pageChanged:) forControlEvents:UIControlEventValueChanged];
以及该委托功能:
-(void)pageChanged:(UIPageControl*)thePageControl;
这个名字可以是你想要的;我用“pageChanged”作为例子。回调签名可以是pageChanged,pageChanged:或pageChanged:forEvent:。此回调函数应该导致您的滚动视图(或您有什么)更新。
分页本身通常是通过使用UIScrollView启用分页和隐藏滚动条来完成的。告诉scrollview使用分页和电影逐页神奇地移动;确保捕获该更改以更新UIPageControl的currentPage属性。
答案 3 :(得分:2)
你是对的 - 除了页面底部的点之外,UIPageControl本身不会绘制任何东西;你需要另一种观点来做到这一点。
答案 4 :(得分:1)
要使用Werner Altewischer类,请添加PagedViewDelegate以连接并完成您的课程,如下所示:
@interface ViewController (){
//header view
UIPageControl* headPageControl;
UIScrollView* headScrollView;
PagedView* headerView;
NSMutableArray* headerViews;
}
//header view
-(void)initHeader;
-(void)setHeaderViews:(NSMutableArray*)views;
-(void)addHeaderView:(UIView*)view;
-(void)popHeader;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self initHeader];
[self popHeader];
}
-(void)initHeader
{
float frameWidth = self.view.frame.size.width;
headPageControl = [[UIPageControl alloc]initWithFrame:CGRectMake(0, HEADER_HEIGHT-PAGE_CONTROL_HEIGHT, frameWidth, PAGE_CONTROL_HEIGHT)];
[headPageControl setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.5]];
headerViews = [NSMutableArray array];
headScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, frameWidth, HEADER_HEIGHT)];
headScrollView.showsHorizontalScrollIndicator = NO;
headerView = [[PagedView alloc] initWithFrame:CGRectMake(0, 0, frameWidth, HEADER_HEIGHT)];
headerView.delegate = self;
headerView.pageControl = headPageControl;
headerView.scrollView = headScrollView;
[headerView addSubview:headScrollView];
[headerView addSubview:headPageControl];
[headerView setBackgroundColor:[UIColor darkGrayColor]];
[self.view addSubview:headerView];
}
-(NSUInteger)numberOfPagesInPagedView:(PagedView *)view
{
//NSLog(@"number of pages %i", headPageControl.numberOfPages);
return headPageControl.numberOfPages;
}
-(UIView*)pagedView:(PagedView *)view viewForPageAtIndex:(NSUInteger)page
{
//NSLog(@"open page %i", page);
return [headerViews objectAtIndex:page];
}
-(void)setHeaderViews:(NSMutableArray*)views
{
headerViews = views;
headPageControl.numberOfPages = headerViews.count;
}
-(void)addHeaderView:(UIView*)view
{
[headerViews addObject:view];
headPageControl.numberOfPages = headerViews.count;
}
-(void)popHeader
{
float frameWidth = self.view.frame.size.width;
CGRect _frame = CGRectMake(0, 0, frameWidth, HEADER_HEIGHT);
UIView* v = [[UIView alloc] initWithFrame:_frame];
[v setBackgroundColor:[UIColor greenColor]];
[self addHeaderView:v];
UIView* v0 = [[UIView alloc] initWithFrame:_frame];
[v0 setBackgroundColor:[UIColor purpleColor]];
[self addHeaderView:v0];
UIView* v1 = [[UIView alloc] initWithFrame:_frame];
[v1 setBackgroundColor:[UIColor yellowColor]];
[self addHeaderView:v1];
}