UICollectionView详解四:焦点图

前三节中,我已经对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;
@end

static 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;
}
时间: 2024-10-12 19:02:15

UICollectionView详解四:焦点图的相关文章

iOS开发——UI篇OC篇&amp;UICollectionView详解+实例

UICollectionView详解+实例 实现步骤: 一.新建两个类 1.继承自UIScrollView的子类,比如HMWaterflowView * 瀑布流显示控件,用来显示所有的瀑布流数据 2.继承自UIView的子类,比如HMWaterflowViewCell * 代表着瀑布流数据中的一个单元(一个格子) 3.总结 HMWaterflowView和HMWaterflowViewCell的关系实际上类似于 UITableView和UITableViewCell的关系 二.设计HMWater

Android基础入门教程——8.3.7 Paint API之—— Xfermode与PorterDuff详解(四)

Android基础入门教程--8.3.7 Paint API之-- Xfermode与PorterDuff详解(四) 标签(空格分隔): Android基础入门教程 本节引言: 上节我们写了关于Xfermode与PorterDuff使用的第一个例子:圆角&圆形图片ImageView的实现, 我们体会到了PorterDuff.Mode.DST_IN给我们带来的好处,本节我们继续来写例子练练手, 还记得Android基础入门教程--8.3.2 绘图类实战示例给大家带来的拔掉美女衣服的实现吗? 当时我

UICollectionView详解

今天,将和大家一起学习UICollectionView,UIcollectionView自出来后,一直受追捧,确实好用.今天有朋友问我如何添加heardView,我简单的回答:tableview如何添加,那么CollectionView就怎么添加,后来经过自己实验发现确实不是那回事,所以列出一些自己犯的错误,供大家参考. 1.首先实例化一个 UICollectionViewFlowLayout因为要设置item,itemSize,等一些属性. UICollectionViewFlowLayout

LinearLayout详解四:彻底解决软键盘遮挡输入框的问题

之前把预备知识都介绍完了,话说学以致用,接下来我们要通过重载LinearLayout类来解决软键盘覆盖的问题. 首先阐述一下这个问题,如下图所示: 然后看挡住输入框的情况 然后我们给出xml的源代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:lay

iOS开发- UICollectionView详解+实例

iOS开发- UICollectionView详解+实例 本章通过先总体介绍UICollectionView及其常用方法,再结合一个实例,了解如何使用UICollectionView. UICollectionView 和 UICollectionViewController 类是iOS6 新引进的API,用于展示集合视图,布局更加灵活,可实现多列布局,用法类似于UITableView 和 UITableViewController 类. 使用UICollectionView 必须实现UICol

sas数据读取详解 四种读取数据方式以及数据指针的位置 、读取mess data的两个小工具、特殊的读取技巧、infile语句及其选项(dsd dlm missover truncover obs firstobs)、proc import、自定义缺失值

(The record length is the number of characters, including spaces, in a data line.) If your data lines are long, and it looks like SAS is not reading all your data, then use the LRECL= option in the INFILE statement to specify a record length at least

spark2.x由浅入深深到底系列六之RDD java api详解四

学习spark任何的知识点之前,先对spark要有一个正确的理解,可以参考:正确理解spark 本文对join相关的api做了一个解释 SparkConf conf = new SparkConf().setAppName("appName").setMaster("local"); JavaSparkContext sc = new JavaSparkContext(conf); JavaPairRDD<Integer, Integer> javaPa

android动画详解四 创建动画

· 使用ValueAnimator进行动画 通过指定一些int, float或color等类型的值的集合,ValueAnimator 使你可以对这些类型的值进行动画.你需通过调用ValueAnimator 的某个工厂方法来获得一个ValueAnimator 对象,比如:ofInt(), ofFloat(), 或 ofObject().例如: ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration

UICollectionView详解五:瀑布流

前面四个章节,我已经详细的讲解了UICollectionView的使用,这一节,我用一个非常实用的例子"瀑布流"来进一步说明UICollectionView的强大作用. 先分析一下瀑布流的特点: 1. 所有item的宽度是一致的. 2. 所有item应该是等比例缩放的. 3. 所有item的高度应该是通过实际宽度与缩放比例计算而得出的. 4. 要保证每一列的底部的y值均匀分布,不能偏差很大. 5. 瀑布流不是常规的流式布局,所以应该使用UICollectionViewLayout,对U