ViewをリサイクルするScrollViewの作り方 ( 2 ) コード

前回書いたviewのリサイクル方法を実際にコードで書いて見ました。 .hファイルと.mファイル合わせて200行ぐらいです。 viewの更新タイミングに少し工夫があって、pagingEnabledをONにしたときに できるだけスクロール中に動作が止まらないようにしてあります KKPagerScrollView.h

1
#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

KKPagerScrollView.m

1
#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