#import <UIKit/UIKit.h>
@interface Test19ViewCell : UIView
// 索引
@property (nonatomic, assign) NSUInteger index;
// 文本
@property (nonatomic, copy) NSString *text;
// 文本控件
@property (nonatomic, retain) UILabel *textLabel;
// 图片名称
@property (nonatomic, retain) NSString *imageName;
// 图片控件
@property (nonatomic, retain) UIImageView *imageView;
@end
#import "Test19ViewCell.h"
@implementation Test19ViewCell
@synthesize index = _index;
@synthesize textLabel = _textLabel;
@synthesize text = _text;
@synthesize imageName = _imageName;
@synthesize imageView = _imageView;
- (void)dealloc{
[_textLabel release];
[_text release];
[_imageView release];
[_imageName release];
[super dealloc];
}
- (id)init{
if (self = [super init]) {
self.backgroundColor = [UIColor yellowColor];
}
return self;
}
- (UILabel *)textLabel{
if (_textLabel == nil) {
_textLabel = [[UILabel alloc] initWithFrame:self.bounds];
_textLabel.textAlignment = UITextAlignmentCenter;
_textLabel.backgroundColor = self.backgroundColor;
_textLabel.contentMode = UIViewContentModeCenter;
[self addSubview:_textLabel];
}
return _textLabel;
}
- (void)setText:(NSString *)text{
if (text != nil) {
[_text release];
_text = [text copy];
self.textLabel.text = _text;
}
}
- (UIImageView *)imageView{
if (_imageView == nil) {
CGFloat padding = 2.f;
CGFloat x = padding;
CGFloat y = padding;
CGFloat width = 40;
CGFloat height = 40;
_imageView = [[UIImageView alloc] init];
_imageView.frame = CGRectMake(x, y, width, height);
[self addSubview:_imageView];
}
return _imageView;
}
- (void)setImageName:(NSString *)imageName{
if (imageName != nil) {
[_imageName release];
_imageName = [imageName copy];
self.imageView.image = [UIImage imageNamed:_imageName];
}
}
@end
#import <Foundation/Foundation.h>
@interface Test19ViewController : UIViewController<UIScrollViewDelegate>
// 数据源
@property (nonatomic, retain) NSMutableArray *dataSource;
// 可见的cell集合
@property (nonatomic, retain) NSMutableSet *visibleCells;
// 可循环的cell集合
@property (nonatomic, retain) NSMutableSet *recycledCells;
// UIScrollView
@property (nonatomic, retain) UIScrollView *scrollView;
@end
#import "Test19ViewController.h"
#import "Test19ViewCell.h"
#define kCellSize CGSizeMake(self.view.frame.size.width, 44)
#define kCellSeparatePadding 1.0
@interface Test19ViewController()
// 根据下标设置对应的frame、index、text
- (void)configureCell:(Test19ViewCell *)cell forIndex:(NSUInteger)index;
// 判断index对应的视图是否在可见队列中
- (BOOL)isVisibleCellForIndex:(NSUInteger)index;
// 重用
- (id)dequeueReusableCell;
// 显示文本
- (void)showCells;
@end
@implementation Test19ViewController
@synthesize dataSource = _dataSource;
@synthesize visibleCells = _visibleCells;
@synthesize recycledCells = _recycledCells;
@synthesize scrollView = _scrollView;
- (void)dealloc{
[_dataSource release];
[_visibleCells release];
[_recycledCells release];
[_scrollView release];
[super dealloc];
}
- (void)loadView{
_scrollView = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_scrollView.backgroundColor = [UIColor whiteColor];
_scrollView.delegate = self;
self.view = _scrollView;
}
- (void)viewDidLoad{
[super viewDidLoad];
_recycledCells = [[NSMutableSet alloc] init];
_visibleCells = [[NSMutableSet alloc] init];
_dataSource = [[NSMutableArray alloc] init];
[_dataSource addObject:@"Zero"];
[_dataSource addObject:@"One"];
[_dataSource addObject:@"Two"];
[_dataSource addObject:@"Three"];
[_dataSource addObject:@"Four"];
[_dataSource addObject:@"Five"];
[_dataSource addObject:@"Six"];
[_dataSource addObject:@"Seven"];
[_dataSource addObject:@"Eight"];
[_dataSource addObject:@"Nine"];
[_dataSource addObject:@"Ten"];
[_dataSource addObject:@"Eleven"];
[_dataSource addObject:@"Tewlve"];
[_dataSource addObject:@"Thirdteen"];
[_dataSource addObject:@"Fourteen"];
[_dataSource addObject:@"Fifteen"];
[_dataSource addObject:@"Sixteen"];
[_dataSource addObject:@"Seventeen"];
[_dataSource addObject:@"Eightteen"];
_scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width, (kCellSize.height +kCellSeparatePadding) * [_dataSource count] - kCellSeparatePadding);
[self showCells];
}
#pragma mark - Private Custom Methods
// 根据下标设置对应的frame、index、text
- (void)configureCell:(Test19ViewCell *)cell forIndex:(NSUInteger)index{
// 设置index
cell.index = index;
CGFloat x = 0;
CGFloat y = (kCellSeparatePadding + kCellSize.height) * index;
CGFloat width = kCellSize.width;
CGFloat height = kCellSize.height;
// 设置frame
cell.frame = CGRectMake(x, y, width, height);
// 设置显示文本text
cell.text = [_dataSource objectAtIndex:index];
// 设置显示图片名称
cell.imageName = [NSString stringWithFormat:@"%d.jpeg",index % 8];
}
// 判断index对应的视图是否在可见队列中
- (BOOL)isVisibleCellForIndex:(NSUInteger)index{
BOOL isVisible = NO;
for (Test19ViewCell *cell in _visibleCells) {
if (cell.index == index) {
isVisible = YES;
break;
}
}
return isVisible;
}
// 重用
- (id)dequeueReusableCell{
Test19ViewCell *cell = [_recycledCells anyObject]; // retain count = 1;
if (cell != nil) {
[[cell retain] autorelease]; // retain count = 2 ,but it seems retain count = 1
[_recycledCells removeObject:cell]; // retain count = 1 now and autorelease
}
return cell;
}
// 用于测试实际创建cell的数量
static int testCount = 0;
- (void)showCells{
// 当前UIScrollView的可见区域
CGRect visibleBounds = _scrollView.bounds;
// 此处存在一定的误差
int firstNeededCellIndex = floorf(CGRectGetMinY(visibleBounds) / (kCellSize.height +kCellSeparatePadding));
int lastNeededICellIndex = floorf(CGRectGetMaxY(visibleBounds) / (kCellSize.height +kCellSeparatePadding));
firstNeededCellIndex = MAX(firstNeededCellIndex, 0);
lastNeededICellIndex = MIN(lastNeededICellIndex, [_dataSource count] - 1);
NSLog(@"%d------%d",firstNeededCellIndex,lastNeededICellIndex);
// 循环可见视图,将不在当前可见范围视图添加到循环队列中,然后从父视图中移除
for (Test19ViewCell *cell in _visibleCells) {
if (cell.index < firstNeededCellIndex || cell.index > lastNeededICellIndex) {
[_recycledCells addObject:cell]; // retain count + 1
[cell removeFromSuperview]; // retain count - 1
}
}
// 可见视图的集合减去循环队列的集合
[_visibleCells minusSet:_recycledCells];
// 添加缺少的cell
for (int index = firstNeededCellIndex; index <= lastNeededICellIndex; index ++) {
if (![self isVisibleCellForIndex:index]) {
// 先取循环队列中寻找对应的数据
Test19ViewCell *cell = [self dequeueReusableCell];
// 如果没有找到可用的,则创建一个新的
if (cell == nil) {
cell = [[[Test19ViewCell alloc] init] autorelease];
testCount ++;
}
// 设置下标、frame、text
[self configureCell:cell forIndex:index];
// 将其添加到视图中
[_scrollView addSubview:cell];
// 加入到可见队列中
[_visibleCells addObject:cell];
}
}
}
#pragma mark - UIScrollViewDelegate Methods
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self showCells];
NSLog(@"count ------> %d",testCount);
}
@end