UICollectionView详解四:焦点图

来源:互联网 发布:喵喵喵老师的淘宝店 编辑:程序博客网 时间:2024/05/29 15:14

前三节中,我已经对UICollectionView的基本用法进行了详细的介绍。这一节就UICollectionView的实际使用 --- "焦点图" 进行剖析说明。废话不多说,先看最终实现效果图:


需求说明:

1.准备了五张图片

2.定时滚动显示

3.右下角的分页指示器也实时切换

4.可以手动拖拽图片滚动


为什么选择UICollectionView?

1.UICollectionView帮我们管理好了循环利用cell的问题,不管有多少图片需要滚动,内存中只需要两个cell管理就好了。

2.UICollectionView有Section的概念,可以准备很多组,但又不需要准备重复的图片来完成无限滚动。

3.UICollectionView有scrollToItemAtIndexPath方法,来实现切换图片动画的流畅过度。


大致代码如下:

1.准备数据模型(上图中的图片及标题)

@interface LFAdvertise : NSObject@property (nonatomic,copy) NSString *title;@property (nonatomic,copy) NSString *url;@end

2.自定义UICollectionViewCell,用来显示模型数据

@class LFAdvertise;@interface LFAdvertiseCell : UICollectionViewCell@property (weak, nonatomic) IBOutlet UILabel *adTitle;@property (weak, nonatomic) IBOutlet UIImageView *adImage;@property (nonatomic,strong) LFAdvertise *advertise;@end@implementation LFAdvertiseCell- (void)setAdvertise:(LFAdvertise *)advertise {    self.adTitle.text = [NSString stringWithFormat:@"  %@",advertise.title];    self.adImage.image = [UIImage imageNamed:advertise.url];}@end

3.主界面代码

1) 定义变量部分: kNumberofSection 定义UICollectionView有多少组;ads就是LFAdvertise 数据模型的集合;timer就是定时执行滚动的定时器; identifer 是UICollectionView循环利用cell的标示符。

#define kNumberofSections 100@interface ViewController ()<UICollectionViewDataSource,UICollectionViewDelegate>@property (nonatomic,strong) NSArray *ads;@property (nonatomic,strong) NSTimer *timer;@endstatic NSString *const identifer = @"news";

2) 获取数据源

-(NSArray *)ads {    if (!_ads) {        _ads = [LFAdvertise objectArrayWithFilename:@"ad.plist"];        // 根据模型数据获得总有有多少页        self.pageControl.numberOfPages = _ads.count;    }    return _ads;}

3) 初始化UICollectionView,为什么将kNumberofSection定义为100? 因为防止用户疯狂的滑动图片看下一张,如果kNumberofSection定义的很小的话,有可能后面就没有图片了。但你有可能有疑问?就算定义为100,也有可能过很长时间后,后面也没有图片了,这个细节操作,我们可以在定时器中处理。

- (void)initCollectionView {    // 1. 注册LFAdvertiseCell    [self.collectionView registerNib:[UINib nibWithNibName:@"LFAdvertiseCell" bundle:nil] forCellWithReuseIdentifier:identifer];        // 2. 默认显示在第几组(正中间:假设有100组,默认显示在第50组)    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:kNumberofSections / 2] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];}

4) 定时器定时滚动图片

- (void)addTimer {    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(unlimitedScroll) userInfo:nil repeats:YES];    self.timer = timer;    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];}// 这里就实现了无限滚动的效果- (void)unlimitedScroll {    // 1. 获取正在界面上显示的item项    NSIndexPath *indexPath = [[self.collectionView indexPathsForVisibleItems] lastObject];    // 2. 每次进来就让用户看中间那组的信息,立刻看到,没有动画(第50组)    NSIndexPath *currentIndexPathReset = [NSIndexPath indexPathForItem:indexPath.item inSection:kNumberofSections / 2];    [self.collectionView scrollToItemAtIndexPath:currentIndexPathReset atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];        // 3. 获取下一张图片的信息    NSInteger nextItem = currentIndexPathReset.item + 1;    NSInteger nextSection = currentIndexPathReset.section;        if(nextItem == self.ads.count){        nextItem = 0;        nextSection++;    }        NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:nextItem inSection:nextSection];        [self.collectionView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];    }

关键代码有两句:

I)  每次定时器执行下面代码的时候,就将图片无动画的拖拽到中间那组的图片位置,注意scrollToItemAtIndexPath方法中,animated的参数值为NO。这里就可以解释为什么可以无限滚动了。假设图片组已经滚动到80组了,下次定时器再执行的时候,会先执行下面的代码,将图片组拉回到第50组对应图片的位置,由于这次操作是无动画的,所以用户根本察觉不出来。

    // 2. 每次进来就让用户看中间那组的信息,立刻看到,没有动画(第50组)    NSIndexPath *currentIndexPathReset = [NSIndexPath indexPathForItem:indexPath.item inSection:kNumberofSections / 2];    [self.collectionView scrollToItemAtIndexPath:currentIndexPathReset atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];


II) 然后最后两句代码,计算出当前图片的下一张图片的位置,再动画执行过去,看起来就是无限滚动了。注意scrollToItemAtIndexPath方法中,animated的参数值为YES。

NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:nextItem inSection:nextSection];        [self.collectionView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];

5) UICollectionView的数据源方法

#pragma mark - UICollectionViewDataSource- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return self.ads.count;}- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {    return kNumberofSections;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    LFAdvertiseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifer forIndexPath:indexPath];        cell.advertise = self.ads[indexPath.item];        return cell;}

6) UICollectionView父类UIScrollView的代理方法,当用户拖拽图片的时候,立刻停止定时器,当用户停止拖拽图片的时候,立刻重新启用定时器。

#pragma mark - UIScrollViewDelegate- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {    [self removeTimer];}- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {    [self addTimer];}- (void)removeTimer {    [self.timer invalidate];    self.timer = nil;}

7) 停止滚动的时候,计算页码:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {    // 加0.5:因为有可能用户手动滚到一张图片的一半左右松手    int numberofPage = (int)(scrollView.contentOffset.x / self.collectionView.frame.size.width + 0.5) % self.ads.count;    self.pageControl.currentPage = numberofPage;}


1 0