Tôi đã viết một lớp (PagedView) hoạt động giống như UITableView và hợp nhất các khái niệm về UIPageControl và UIScrollView theo cách được sử dụng ví dụ trên màn hình chính của iPhone.
Khái niệm cơ bản như sau: bạn cần triển khai PagedViewDelegate để trả về số trang và chế độ xem cho mỗi trang của bạn PagedView. Việc sử dụng lại lượt xem hoạt động giống như trong UITableView. Sử dụng trình tạo giao diện để kết nối các cửa sổ scrollview và pageControl.
Vui lòng cho tôi biết nếu bạn thấy lớp học này hữu ích.
.h-file:
//
// 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 file:
//
// 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
Nguồn
2010-10-25 11:49:25
@Warner: bạn có thể vui lòng expalin làm thế nào tôi có thể sử dụng lớp này? –
Hi Werner, bạn có thể cung cấp một cách đơn giản bằng cách sử dụng lớp này làm ví dụ không? Có lẽ bạn có thể muốn đăng nó trên github. – ardochhigh
Để sử dụng, chỉ cần thêm vào hai phương thức ViewController của bạn: – HotJard