
准备数据
首先先加入一些资源文件:app
先创建一个xcassets
文件,放入图片:ide

再创建一个plist文件,写入与图片对应的内容:布局

在ViewController中读取plist
到词典中:post
@property (nonatomic, strong) NSArray *itemTitles;
NSString *path = [[NSBundle mainBundle] pathForResource:@"titles" ofType:@"plist"]; NSDictionary *rootDictionary = [[NSDictionary alloc] initWithContentsOfFile:path]; self.itemTitles = [rootDictionary objectForKey:@"heros"];
|
能够打log
输出,能够看到plist
的内容已经读取出来,后面就能够用_itemTitle
做为数据源了。优化
添加UICollectionView初步显示图片
每一个CollectionView
都有一个对应的布局layout
,对于默认的的UICollectionViewFlowLayout
,效果是相似Android的GridView
的布局。若是要自定义CollectionView
的样式,就要对这个layout
进行修改。ui
创建本身的HorizontalFlowLayout
,继承自UICollectionViewFlowLayout
,而后在初始化方法里将滚动方向设置为水平:atom
- (instancetype) init { if (self = [super init]) { self.scrollDirection = UICollectionViewScrollDirectionHorizontal; } return self; }
|
接下来定制咱们的cell
的显示样式,创建DotaCell
,继承自UICollectionViewCell
。因为咱们要实现的是图片和文字的上下布局,因此增长两个属性:spa
@interface DotaCell : UICollectionViewCell
@property (nonatomic, strong) UIImageView *image; @property (nonatomic, strong) UILabel *name;
@end
|
而后设置图片与文字上下对齐布局,这里我使用pod
导入Masonry
库来写自动布局:代理
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self initialize]; } return self; }
- (void)initialize { self.layer.doubleSided = NO; self.image = [[UIImageView alloc] init]; self.image.backgroundColor = [UIColor clearColor]; self.image.contentMode = UIViewContentModeCenter; self.image.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.name = [[UILabel alloc] init]; self.name.font = [UIFont fontWithName:@"Helvetica Neue" size:20]; self.name.textAlignment = NSTextAlignmentCenter; [self.contentView addSubview:self.image]; [self.contentView addSubview:self.name];
[_image mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.contentView); make.top.equalTo(self.contentView).offset(30); make.bottom.equalTo(_name.mas_top).offset(-10); }]; [_name mas_makeConstraints:^(MASConstraintMaker *make) { make.left.right.equalTo(self.contentView); make.top.equalTo(_image.mas_bottom).offset(10); make.bottom.equalTo(self.contentView).offset(-20); }]; }
|
写好layout
和cell
后就能够用这两个类来初始化咱们的collectionView
了:code
添加UICollectionViewDataSource
的代理方法,使其显示数据。
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.itemTitles count]; }
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { DotaCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([DotaCell class]) forIndexPath:indexPath]; cell.image.image = [UIImage imageNamed:[self.itemTitles objectAtIndex:indexPath.row]]; cell.name.text = [self.itemTitles objectAtIndex:indexPath.row]; return cell; }
|
这样程序就有了咱们想要的初步效果:

图片水平排放
但…效果的确不好!
下面要作的就是逐步完善效果,首先咱们要让两排图像变成一排去展现。那要怎么去作?首先,咱们在初始化collectionView
的地方设置了高度为150,因此图片就挤在这个150的高度里尽量的压缩显示。因为collectionView
的尺寸已经设定,那么就剩cell
的尺寸能够控制了。实现CollectionViewFlowLayoutDelegate
的代理方法sizeForItemAtIndexPath
:
- (CGSize)collectionView:(nonnull UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { return CGSizeMake(64, collectionView.bounds.size.height); }
|
这里宽度64是图片的尺寸,高度设置填满collectionView
的高度是为了防止上图中两行图片挤压的状况,因此直接让一个cell
的高度占满整个容器。
这时候的效果好了不少,已经有点样子了:

顶端图片滑到中间
但这离咱们最终的效果还差很远,接下来我须要实现让第一张图片和最后一张图片都能滑到屏幕中点的位置,这应该是很常见的效果,实现起来也很简单。首先咱们的一排cell
都默认为顶端与collectionView
的两端对齐的,collectionView
的左右两端与viewController.view
也是对齐的,因此显示的效果是,两端的图片都与屏幕对齐。知道这个关系就好办了,直接设置collectionView
与其父view
的内间距便可。
依旧是实现flowLayout
的代理方法:
效果如图:

居中图片放大显示
接下来添加一个咱们须要的特效,就是中间的图片放大显示,其他的缩小而且增长一层半透明效果。
在FlowLayout
中有一个名为layoutAttributesForElementsInRect
的方法,功能如其名,就是设置范围内元素的layout
属性。对于这个效果,首先须要设置放大的比例,其次要根据图片大小和间距来设定一个合适的触发放大的区域宽度,当图滑入这个区域就进行缩放。
static CGFloat const ActiveDistance = 80; static CGFloat const ScaleFactor = 0.2;
|
效果以下:

滑动校订
这时候几乎完成了,但还差点东西,就是让其在滚动中止的时候,离屏幕中间最近的cell
自动矫正位置到中间。仍是在FlowLayout
添加该方法,具体说明我都写到注释里了:

增长图片点击效果
最后 添加一个点击cell 将其滚动到中间
在viewcontroller
添加CollectionViewDelegate
的代理方法
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { [self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; |

封装成控件
当咱们把效果实现以后,就能够考虑将代码优化一下,合到一个类里,减小书写常量,增长接口,封装成一个控件去使用。好比能够设定文字的显示与隐藏接口,再好比增长适应各类尺寸的图片等等。这个代码就不放了,毕竟不难,有问题给我留言好了。