UIScrollView实现重用机制(类似多列tableview)

来源:互联网 发布:淘宝sc面膜是正品吗 编辑:程序博客网 时间:2024/05/22 03:32

要显示多列数据,在ios6之前可以通过自定义cell来实现,在ios6之后则可以使用UICollectionView。当然也有一种办法就是直接使用UIScrollView。不过UIScrollView并不像UITableview一样有重用机制,如果不经处理就加载多条数据,就会大量占用内存,程序越来越卡。本文的主题就是为UIScrollView实现重用机制,避免内存浪费。


总体的思路比较简单,就是在移动UIScrollView时判断其子视图在不在屏幕上,不在的话就将其移动。


下面直接上代码

@interface WLViewController : UIViewController<UIScrollViewDelegate>{    NSInteger cellViewHeight;    NSInteger cellViewWide;    NSInteger countOfRow;    //一行的view个数    NSInteger queueCount;    //队列里元素的个数          NSInteger dataIndex;    NSInteger maxRow;    NSInteger queueIndex;    NSInteger preIndex;    NSInteger maxindex;}-(void)loadDataOfCell:(UIView *) cell;-(void) cellHasBeensSlected:(NSInteger)inedx;-(void)writeCell:(UIView *)cell;-(void)readCell:(UIView *)cell withIndex:(NSInteger)index;


@interface WLViewController ()@property (nonatomic,strong) NSMutableArray *dataSure; //用来存放数据,应该是存做文件,为了简单,就先放在数组里@property (nonatomic,strong) NSMutableArray *viewQueue; //队列,通过更改队列里视图的矩形位置来实现滚动@property (nonatomic,strong) UIScrollView *mainView;@end@implementation WLViewController-(id)init{    return  [self initWithCountOfRow:4];}-(id)initWithCountOfRow:(NSInteger)count{    self = [super init];    if(self)    {        countOfRow =count;        cellViewHeight = cellViewWide = 320 / countOfRow;        queueCount = countOfRow * 800 / cellViewHeight;        queueCount -= countOfRow % 2 == 0 ? 0 : countOfRow / 2;        self.dataSure = [[NSMutableArray alloc] init];    }        return self;}- (void)viewDidLoad{    [super viewDidLoad];        self.viewQueue = [[NSMutableArray alloc] init];    self.mainView = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    self.mainView.contentSize = CGSizeMake(320, 800);    self.mainView.delegate = self;    [self.view addSubview:self.mainView];            for(int i = 0; i < queueCount; i++)    {        CGRect rect = CGRectMake(i % countOfRow * cellViewWide, i / countOfRow * cellViewHeight, cellViewWide, cellViewHeight);                        AlbumView *album = [[AlbumView alloc] initWithFrame:rect];        [self.mainView addSubview:album];        [self.viewQueue addObject:album];        [self loadDataOfCell:album];        dataIndex++;    }        maxRow = 0;    queueIndex = 0;    }- (void)scrollViewDidScroll:(UIScrollView *)scrollView{    //防止开始就向上滑    if(scrollView.contentOffset.y <= 0)        return;        int p = (int)scrollView.contentOffset.y / cellViewHeight;    if(p >= maxRow)    {        //增加MAINVIEW的长度        [self addRows:p / 2 + 1];        maxRow = (self.mainView.contentSize.height - cellViewHeight * queueCount / countOfRow) / cellViewHeight;    }        if(p > preIndex)    {        [self pullDown:p-preIndex];            }    else if (p < preIndex)    {        [self pullUp:preIndex - p];    }        preIndex = p; //记录前一位置    if(dataIndex >= maxindex) maxindex = dataIndex;}-(void)addRows:(NSInteger)counts{    CGSize size = self.mainView.contentSize;    size.height += cellViewHeight * counts;    self.mainView.contentSize = size;}-(void)pullDown:(NSInteger)count{        for(int i = 0; i < countOfRow * count; i++)    {        AlbumView *album = [self.viewQueue objectAtIndex:queueIndex];        album.frame = CGRectMake(dataIndex % countOfRow * cellViewWide, dataIndex / countOfRow * cellViewHeight, cellViewWide, cellViewHeight);                //如果没加载数据,就加载数据,如果已经加载过(向上滑动后又滑下),因为已经加载过一次,所以就直接读取                if(dataIndex >= maxindex)            [self loadDataOfCell:album];        else            [self readCell:album withIndex:dataIndex];                dataIndex++;        //变更换队列的索引,指向下一个将要使用的视图        queueIndex = queueIndex + 1 == queueCount ? 0: queueIndex + 1;    }}-(void)pullUp:(NSInteger)count{    for(int i = 0; i < countOfRow * count; i++)    {        dataIndex--;        queueIndex = queueIndex == 0 ? queueCount - 1: queueIndex - 1;                AlbumView *album = [self.viewQueue objectAtIndex:queueIndex];        album.frame = CGRectMake(dataIndex % countOfRow * cellViewWide, (dataIndex / countOfRow  - queueCount / countOfRow ) * cellViewHeight, cellViewWide, cellViewWide);                //向上滑动只需要读取之前加载的视图        [self readCell:album withIndex:dataIndex - queueCount];    }}-(void)loadDataOfCell:(UIView *)cell{        //获取数据源,如果从文件获取,则需要判断是否已经存在该文件。这里只是简化的写法。    [(AlbumView *)cell dosome];    ((AlbumView *)cell).i = dataIndex;        [self writeCell:cell];    }-(void) cellHasBeensSlected:(NSInteger)inedx{    //钩子方法,在MAINVIEW的子视图被点击时调用    NSLog(@"------%d",inedx);}-(void)writeCell:(UIView *)cell{    //写方法,这里只简单的把视图的数据写入数组    AlbumView *album = [[AlbumView alloc] init];    album.backgroundColor = cell.backgroundColor;    album.i = dataIndex;        [self.dataSure addObject:album];}-(void)readCell:(UIView *)cell withIndex:(NSInteger)index{    /// /读方法,同上    AlbumView *subview = [self.dataSure objectAtIndex:index];    cell.backgroundColor = subview.backgroundColor;    ((AlbumView *)cell).i = subview.i;}@end


为了实现钩子方法,这里选择写UIScrollView的分类的方式实现

@implementation UIScrollView (AlbumViewController)- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{    UITouch *touch = [touches anyObject];    if(![self.nextResponder.nextResponder isMemberOfClass:[WLViewController class]]) return;        AlbumView *album = (AlbumView *)[self hitTest:[touch locationInView:self] withEvent:event];    [(WLViewController *)self.nextResponder.nextResponder cellHasBeensSlected:album.i];    }@end


最后是AlbumView类,这个类很随意。

@interface AlbumView : UIView@property (nonatomic) NSInteger i;-(void)dosome;@end

@implementation AlbumView-(void)dosome{    CGFloat r = (CGFloat)(arc4random() % 10) / 10.0;    CGFloat g = (CGFloat)(arc4random() % 10) / 10.0;    CGFloat b = (CGFloat)(arc4random() % 10) / 10.0;    self.backgroundColor = [UIColor colorWithRed:r green:g blue:b alpha:1.0];}@end


一个简单的dome,只是简单的提供一个思路,如果投入使用的话还得进行一些细微的调整,例如,后台加载数据,以及等待数据加载时应该转菊花来增加用户体验等。

上传两张效果图



4 0
原创粉丝点击