iOS 投机流实现 无限轮播图

来源:互联网 发布:淘宝怎么加好友 编辑:程序博客网 时间:2024/05/28 14:56

无限轮播图, 这种简单的功能没什么技术含量, 实现的方式也各种各样, 技术含量较高的分为:
1) UIScrollView二图流(就是两张图之间来回切换) 这个对算法的要求比较高, 一般不推荐自己写, 使用网上现成封装好的就好啦.
2) UICollectionViewLayout布局流(使用自定义Layout布局) 这种对算法要求极高, 不过一劳永逸, 使用方便快捷低耦合.

还有其他的实现的方法我也不一一列举, 在SQExtension中也有封装好的SQInfiniteCell可以使用, 今天我推荐的方法是投机流 那什么是投机流呢, 且听我娓娓道来. 先回到我们的项目, 经过设计图分析,首先我们先将导航栏进行隐藏, 隐藏的方式各种各样, 可以直接setHidden但是为了我们之后的功能, 先按如下设置:

隐藏导航栏
- (void)loadView {    [super loadView];    [self.navigationItem setTitleView:[UIView new]];    [self.navigationController.navigationBar setBackgroundImage:[UIImage imageWithColor:[UIColor clearColor]] forBarMetrics:UIBarMetricsDefault];    [self.navigationController.navigationBar setShadowImage:[UIImage imageWithColor:[UIColor clearColor]]];}

隐藏导航栏 我选择的方式是将导航栏填充透明背景色而不是将其隐藏. setTitleView是因为之前的框架有KVO属性, 接下来我们将tableView向上偏移64_tableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);

- (UITableView *)tableView {    if (!_tableView) {        _tableView = [UITableView new];        _tableView.frame = self.view.bounds;        _tableView.dataSource = self;        _tableView.delegate = self;        _tableView.contentInset = UIEdgeInsetsMake(-64, 0, 0, 0);    }    return _tableView;}

这样我们几步简单的操作, 就将导航栏给隐藏了, 接下来我们需要自定义Cell.

自定义cell

自定义Cell 的方式也是各有不同, 写法也大不一样, xib, 代码流等等, 我是属于纯代码流的, 并不是说我不会用AutoLayout, 而是我觉得用xib写自定义控件的效率和可维护性 还是比较低下的, 但这是今后的趋势Apple的开发这种可见即可得的出发点就是让我们不用关心展示层, 而更加关心业务逻辑.

扯远了… 我们现在使用纯代码, 之前我有讲过代码库这个功能, 就不过多赘述, 我们使用代码库在.h文件和.m文件中添加:

.h
+ (instancetype)cellWithTableView:(UITableView *)tableView;+ (CGFloat)cellHeight;
.m
+ (instancetype)cellWithTableView:(UITableView *)tableView {    NSString * identifier = NSStringFromClass([<#class#> class]);    <#class#> * cell = [tableView dequeueReusableCellWithIdentifier:identifier];    if (!cell) {        cell = [[<#class#> alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];    }    return cell;}- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];    if (self) {        [self setupSubviews];    }    return self;}- (void)setupSubviews {}- (void)layoutSubviews {    [super layoutSubviews];}+ (CGFloat)cellHeight {    return <#cellHeight#>;}

接着我们在tableView的cellForRowheightForRow代理方法中添加:

cellForRow
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    SQBannerCell * cell = [SQBannerCell cellWithTableView:tableView];    return cell;}
heightForRow
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    return [SQBannerCell cellHeight];}

这样我们的自定义Cell就算完成了, 非常简单快捷吧, 接下来我们要实现轮播图的功能!

实现无限滚动

现在我们就来说说这个投机流是怎么一回事. 我们还是使用UICollectionView 因为这样就不用我们自己来做复用缓存池啦 cell.contentView.layer.contents = (__bridge id)[UIImage imageNamed:@"banner"].CGImage; 这个是layer的寄宿图属性, 不懂得同学可以Google一下. (我只是偷懒 ^ ^)

创建CollectionView
- (UICollectionViewFlowLayout *)flowLayout {    if (!_flowLayout) {        _flowLayout = [UICollectionViewFlowLayout new];        _flowLayout.minimumInteritemSpacing = 0.0f;        _flowLayout.minimumLineSpacing = 0.0f;        _flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;    }    return _flowLayout;}- (UICollectionView *)collectionView {    if (!_collectionView) {        _collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];        _collectionView.dataSource = self;        _collectionView.delegate = self;        _collectionView.pagingEnabled = YES;        _collectionView.bounces = NO;        _collectionView.showsHorizontalScrollIndicator = NO;        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];    }    return _collectionView;}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {    UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];    cell.contentView.layer.contents = (__bridge id)[UIImage imageNamed:@"banner"].CGImage;    return cell;}
布局collectionView
- (void)layoutSubviews {    [super layoutSubviews];    self.flowLayout.itemSize = self.contentView.bounds.size;    self.collectionView.frame = self.contentView.bounds;}

到这一步我们collectionView算是完成 但怎么完成无线滚动呢? 说好的投机呢?

投机流大揭秘

使用全局来替换宏 这样的性能会好一点

static const NSInteger kMultiply = 500;static const NSInteger kCounts = 5;

这算神马投机?? 表示看不懂啊有木有!! 不急接着往下看!!

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {    return kCounts * kMultiply;}

在layoutSubviews中添加如下代码

- (void)layoutSubviews {    [super layoutSubviews];    self.flowLayout.itemSize = self.contentView.bounds.size;    self.collectionView.frame = self.contentView.bounds;    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:kCounts * kMultiply * 0.5f inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];}

这样我们就完成了无限轮播了, 不信你试试, 相信聪明的同学已经看懂了, 没错就是在collectionView创建完之后让他从中间开始走, kCounts代表你数据源有几条数据,kMultiply代表着你的乘积, 其实并不是真正的无限循环, 但效果已经达到了不是, 坏笑~~ (用户不可能一直翻翻翻,翻个500多下吧, 脑残除外) 接下来继续分析设计图, 发现在pageControl下面有一个浮雕层, 我们把这张图片给添加进来, (使用Ps切图工具 CMD + C)

- (UIImageView *)reliefArcImageView {    if (!_reliefArcImageView) {        _reliefArcImageView = [UIImageView new];        _reliefArcImageView.image = [UIImage imageNamed:@"RelliefArc"];    }    return _reliefArcImageView;}- (UIPageControl *)pageControl {    if (!_pageControl) {        _pageControl = [UIPageControl new];        _pageControl.hidesForSinglePage = YES;        _pageControl.defersCurrentPageDisplay = YES;        _pageControl.numberOfPages = kCounts;        _pageControl.pageIndicatorTintColor = KC05_dddddd;        _pageControl.currentPageIndicatorTintColor = KC01_57c2de;    }    return _pageControl;}- (void)setupSubviews {    [self.contentView addSubview:self.collectionView];    [self.contentView addSubview:self.reliefArcImageView];    [self.contentView addSubview:self.pageControl];}- (void)layoutSubviews {    [super layoutSubviews];    self.flowLayout.itemSize = self.contentView.bounds.size;    self.collectionView.frame = self.contentView.bounds;    [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:kCounts * kMultiply * 0.5f inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];    CGFloat reliefArcImageViewX = 0;    CGFloat reliefArcImageViewH = kScaleLength(50);    CGFloat reliefArcImageViewY = self.height - reliefArcImageViewH;    CGFloat reliefArcImageViewW = self.width;    self.reliefArcImageView.frame = CGRectMake(reliefArcImageViewX, reliefArcImageViewY, reliefArcImageViewW, reliefArcImageViewH);    CGFloat pageControlX = 0;    CGFloat pageControlH = 35;    CGFloat pageControlY = self.collectionView.bounds.size.height - pageControlH;    CGFloat pageControlW = self.collectionView.bounds.size.width;    self.pageControl.frame = CGRectMake(pageControlX, pageControlY, pageControlW, pageControlH);}

接着我们在scrollViewDidScroll代理方法中添加,至此无限轮播大功告成!!

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {    self.pageControl.currentPage = ((NSInteger)((scrollView.contentOffset.x + self.contentView.frame.size.width) / self.contentView.frame.size.width) - 1) % kCounts;}
添加定时器

接下来我们要做的就是添加定时器的功能了, 让其自动的轮播! 其实非常之简单!!

1) 在初始化的时候添加定时器 [self setupTimer];
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];    if (self) {        [self setupTimer];        [self setupSubviews];    }    return self;}
2) 配置定时器功能
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {    [self.timer invalidate];}- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {    [self setupTimer];}- (void)setupTimer {    if ([self respondsToSelector:@selector(updateTimer)]) {        self.timer = [NSTimer timerWithTimeInterval:5.0f target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];        [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];    }}- (void)updateTimer {    [self.collectionView setContentOffset:CGPointMake(self.collectionView.contentOffset.x + self.contentView.frame.size.width, 0) animated:YES];}

到这 我们今天的功能就全部结束了, 投机流是不是非常简单高效快捷呢 哈哈哈~~~

在Reveal中显示

最终显示

具体源码及SQExtension方法信息 请到github上进行下载!



文/Doubles_Z(简书作者)
原文链接:http://www.jianshu.com/p/e42db267d5f1
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
0 0
原创粉丝点击