您的位置:首页 > 产品设计 > UI/UE

iOS开发学习之无限滚动UICollectionView和BUG解决措施

2015-09-21 10:54 561 查看
(一) 无限滚动之UICollectionView
您好、
平时我们经常在图片浏览器中会翻看一些图片,对于这会滚动的效果实现,我们第一个直觉会想到的UIscrollview。首先我们会考虑到View的一些循环利用,一般情况下会创建两到三个View去实现它的来回的切换滚动。

不过今天虾米没用到这种方法。虾米用的是UICollectionView。
那下面 小虾米通过小作业来实现无限滚动,如果当中有什么不好的或者是需要改善的地方,请告诉我您的建议和意见。同时也可以联系虾米。
我们私下可以交流交流。。。。xieixe!!

自动滚动大致意图:



虾米先把大体需要用到的类都放在每一个对应位置上,方便以后查找某一个类和元素。
先浏览一下整体的classes。然后虾米再附上每一个类的代码实现 。 如下图:



我们先在故事板里,拉入一个UICollectionView(最好和图片的尺寸一样 )和一个UIPageController。如下图:
注意:根控制器的class要改为JHNewsController. 并且collectionView的代理和数据源方法为self(根控制器)
可以在collectionView上右击拉线给News Controller或者用代码实现。。。^-^ 嘻嘻。。。



然后,在根控制器当中我们必须遵守UICollectionView的一些协议。
虾米先把根控制器的主要实现代码po上。

大致为:
通过添加一个定时器实现三组数据的无限循环滚动。
主要方法是   [self.collectionView scrollToItemAtIndexPath: atScrollPosition: animated:YES]; 同时也要计算出需要展示的位置。
自动滚动下一页请详细看看我下面所写的方法 -(void)nextPage。

代码如下:
//  JHNewsController.m
//  无限滚动-02新闻数据显示
//
//  Created by cjj on 15-9-19.
//  Copyright (c) 2015年 jh.chen. All rights reserved.
//

#import "JHNewsController.h"
#import "JHNewsCell.h"
#import "JHNews.h"
#import "MJExtension.h"

#define JHReuseIdentifierCell @"news"
#define JHMaxSection 3

@interface JHNewsController () <UICollectionViewDataSource,UICollectionViewDelegate>
@property (nonatomic, strong) NSArray *newses;
@property (nonatomic, strong) NSTimer *timer;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;

@end

@implementation JHNewsController
- (NSArray *)newses
{
if (_newses == nil) {
self.newses = [JHNews objectArrayWithFilename:@"newses.plist"];
self.pageControl.numberOfPages = self.newses.count;
}
return _newses;
}

- (void)viewDidLoad
{
[super viewDidLoad];

// 注册cell
[self.collectionView registerNib:[UINib nibWithNibName:@"JHNewsCell" bundle:nil] forCellWithReuseIdentifier:JHReuseIdentifierCell];

// "默认"显示最中间那组
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:JHMaxSection / 2] atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];

// 添加定时器
[self addTimer];
}

/*
*  添加定时器
*/
-(void)addTimer
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextPage) userInfo:nil repeats:YES];

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
self.timer = timer;
}

-(void)nextPage
{
// 1.显示当前的位置信息
NSIndexPath *currentIndexPath = [[self.collectionView indexPathsForVisibleItems] lastObject];

// 马上显示中间那组的数据
NSIndexPath *currentIndexPathReset = [NSIndexPath indexPathForItem:currentIndexPath.item inSection:JHMaxSection / 2];
[self.collectionView scrollToItemAtIndexPath:currentIndexPathReset atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

// 2.计算出下一个需要展示的位置
NSUInteger nextItem = currentIndexPathReset.item + 1;
NSUInteger nextSection = currentIndexPathReset.section;
if (nextItem == self.newses.count) {
nextItem = 0;
nextSection ++;
}
NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:nextItem inSection:nextSection];

// 3.通过动画滚动到下一个位置
[self.collectionView scrollToItemAtIndexPath:nextIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}

/*
*  移除定时器
*/
-(void)removeTimer
{
[self.timer invalidate];
self.timer = nil;
}

#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.newses.count;
}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return JHMaxSection;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
JHNewsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:JHReuseIdentifierCell forIndexPath:indexPath];

cell.news = self.newses[indexPath.item];

return cell;
}

#pragma mark - UICollectionViewDelegate

/**
*  当用户开始拖拽时就会调用
*/
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self removeTimer];
}

/**
*  当用户停止拖拽时就会调用
*/
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
[self addTimer];
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 显示下一页
int page = (int)(scrollView.contentOffset.x / scrollView.bounds.size.width + 0.5) % self.newses.count;
self.pageControl.currentPage =page;
}

@end


另外。。。我们有必要了解下JHNewsCell,虾米通过继承UICollectionViewCell,并创建附有一个Xib属性。里面封装着一个UIImageView和一个UILabel。
.h文件留下一个接口,让别人传递数据进来,我们拿到外边传进来的数据在.m文件通过set方法实现。。。

详细代码如下:

//
//  JHNewsCell.m
//  无限滚动-02新闻数据显示
//
//  Created by cjj on 15-9-19.
//  Copyright (c) 2015年 jh.chen. All rights reserved.
//

#import "JHNewsCell.h"
#import "JHNews.h"

@interface JHNewsCell()

@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIImageView *iconView;

@end

@implementation JHNewsCell

- (void)setNews:(JHNews *)news
{
_news = news;
self.iconView.image = [UIImage imageNamed:news.icon];
self.titleLabel.text = [NSString stringWithFormat:@"  %@",news.title];
}

@end


(二) BUG解决措施
在写这份demo的时候,遇到一些让我纠结了半天而程序莫名崩溃的bug,为此虾米把它记录了下来。
上面写的代码,检查了很多遍都没有问题。但运行时出现了错误,报如下的错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'invalid nib registered for identifier (news) - nib must contain exactly one top level object which must be a UICollectionReusableView instance’

最终还是被我找到了错误原因:在自定义xib的时候,额外多了一个控件在cell另外的区域,把该控件删除即可。
如图:



把多余的UIImageView删除即可,说到底还是自己太马虎从而犯了简单的错误了。

如果有什么好的建议,请联系虾米,虾米感激不尽 蟹蟹 哈!!




虾米联系方式:
QQ:584837022
github:https://github.com/ios-cjh
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息