前回書いたviewのリサイクル方法を実際にコードで書いて見ました。
.hファイルと.mファイル合わせて200行ぐらいです。

viewの更新タイミングに少し工夫があって、pagingEnabledをONにしたときに
できるだけスクロール中に動作が止まらないようにしてあります


KKPagerScrollView.h

[objc]
#import <Foundation/Foundation.h>
#import "KKPagerScrollViewDataSource.h"

@interface KKPagerScrollView : UIScrollView<UIScrollViewDelegate>{
NSMutableSet *_viewCache;
NSMutableDictionary *_displayedView;
id<KKPagerScrollViewDataSource> _dataSource;
int _numberOfContents;
NSRange _displayedRange;

}

@property(readonly,nonatomic) int pageIndex;
@property(readonly,nonatomic) NSRange rangeOfVisibleContents;
@property(assign,nonatomic) id<KKPagerScrollViewDataSource> dataSource;

- (UIView *)viewAtIndex:(int)index;
- (UIView *)dequeueReusableView;

- (CGPoint)centerOfPageIndex:(int)index;
- (void)removeViewAtIndex:(int)index;
- (void)refresh;
- (void)reload;
- (void)addPages;
- (void)moveToNextPage;
- (void)moveToPrevPage;
- (void)moveToPageIndex:(int)index animated:(BOOL)animated;
@end
[/objc]

KKPagerScrollView.m
[objc]

#import "KKPagerScrollView.h"

@implementation KKPagerScrollView
@synthesize dataSource = _dataSource;

- (id)initWithFrame:(CGRect)frame{
if((self = [super initWithFrame:frame])){
_viewCache = [[NSMutableSet alloc] init];
_displayedView =[[NSMutableDictionary alloc] init];
self.delegate = self;
}
return self;
}

- (void)dealloc{
_dataSource = nil;
KKRelease(_viewCache);
KKRelease(_displayedView);

[super dealloc];
}

- (UIView *)viewAtIndex:(int)index{
NSNumber *key = [NSNumber numberWithInt:index];
UIView *view = [_displayedView objectForKey:key];
if(!view){
view = [_dataSource pagerScrollView:self viewAtIndex:index];
[_displayedView setObject:view forKey:key];
}
return view;
}

-(int)pageIndex{
return floor((self.contentOffset.x / self.bounds.size.width) + 0.5) ;
}

-(NSRange)rangeOfVisibleContents{
int page = floor(self.contentOffset.x / self.bounds.size.width);

int startPageIndex = MAX(0,page – 1);
int lastPageIndex = MIN(_numberOfContents – 1, page + 1);

return NSMakeRange(startPageIndex, lastPageIndex – startPageIndex + 1);
}

- (UIView *)dequeueReusableView{
id obj = [[[_viewCache anyObject] retain] autorelease];
if(obj != nil){
[_viewCache removeObject:obj];
}
return obj;
}

- (CGPoint)centerOfPageIndex:(int)index{
CGPoint center = CGPointZero;
CGSize size = self.bounds.size;

center.x = size.width * (index + 0.5);
center.y = size.height * 0.5;

return center;
}

- (void)removeViewAtIndex:(int)index{
NSNumber *key = [NSNumber numberWithInt:index];
UIView *view = [[[_displayedView objectForKey:key] retain] autorelease];
if(view){
[view removeFromSuperview];
[_displayedView removeObjectForKey:key];
[_viewCache addObject:view];
}
}

-(void)refresh{
NSRange range = [self rangeOfVisibleContents];

//displayedRangeにあってrangeにないものを順番に削除
int maxNumber = _displayedRange.location + _displayedRange.length ;
for(int i = _displayedRange.location ; i < maxNumber; i++){
if(range.location <= i && i < range.location + range.length ){
i = range.location + range.length – 1;
continue;
}
NSLog(@"remove %d page",i);
[self removeViewAtIndex:i];
}

//rangeにあって_displayedRangeにないものを順番に追加
maxNumber = range.location + range.length ;
for(int i = range.location ; i < maxNumber; i++){
if(_displayedRange.location <= i && i < _displayedRange.location + _displayedRange.length ){
i = _displayedRange.location + _displayedRange.length – 1;
continue;
}
NSLog(@"make %d page",i);
UIView *view = [self viewAtIndex:i];
[view setCenter:[self centerOfPageIndex:i]];
[self addSubview:view];
}

_displayedRange = range;
}

- (void)reload{
_numberOfContents = [_dataSource numberOfContentsInPagerScrollView:self];
CGSize viewSize = self.bounds.size;
self.contentSize = CGSizeMake(viewSize.width * _numberOfContents, viewSize.height );

int max = _displayedRange.length + _displayedRange.location;
for(int i = _displayedRange.location; i < max; i++){
[self removeViewAtIndex:i];
}
_displayedRange.length = 0;

[_displayedView removeAllObjects];
[_viewCache removeAllObjects];

[self refresh];
}

- (void)addPages{
_numberOfContents = [_dataSource numberOfContentsInPagerScrollView:self];
CGSize viewSize = self.bounds.size;
self.contentSize = CGSizeMake(viewSize.width * _numberOfContents, viewSize.height );

[self refresh];
}

- (void)moveToNextPage{
[self moveToPageIndex:self.pageIndex + 1 animated:YES];
}

- (void)moveToPrevPage{
[self moveToPageIndex:self.pageIndex - 1 animated:YES];

}

- (void)moveToPageIndex:(int)index animated:(BOOL)animated{
if(index < 0) index = 0;
if(index >= _numberOfContents) index = _numberOfContents – 1;
CGSize viewSize = self.bounds.size;
CGRect visibleRect = CGRectMake(viewSize.width * index, 0, viewSize.width, viewSize.height);
[self scrollRectToVisible:visibleRect animated:animated];

}
#pragma – ScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self refresh];
}
@end

[/objc]

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>