1. 准备数据(都是网上一些图片网址)
self.imageUrls = @[@"http://g.hiphotos.baidu.com/image/pic/item/03087bf40ad162d9ec74553b14dfa9ec8a13cd7a.jpg", @"http://e.hiphotos.baidu.com/image/pic/item/14ce36d3d539b600be63e95eed50352ac75cb7ae.jpg", @"http://b.hiphotos.baidu.com/image/pic/item/f703738da9773912825f6388fc198618377ae2da.jpg", @"http://pic1.win4000.com/pic/7/98/46ff752619.jpg", @"http://pic1.win4000.com/pic/9/2c/5ade1167912.jpg", @"http://g.hiphotos.baidu.com/image/pic/item/03087bf40ad162d9ec74553b14dfa9ec8a13cd7a.jpg", @"http://e.hiphotos.baidu.com/image/pic/item/14ce36d3d539b600be63e95eed50352ac75cb7ae.jpg"];
2. 初步显示图片
创建类 XCCollectionViewLayout 继承自 UICollectionViewFlowLayout,目的就是自定义 CollectionView的样式,对layout进行修改。
- (instancetype)init
{
if (self = [super init]) {
self.minimumLineSpacing = 20;//设置行间距
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;//设置水平滚动
}
return self;
}
接下来制订Cell,这边采用自定义Cell三种方法之一,在storyboard上直接加控件,再创建XCADCollectionViewCell类继承自UICollectionView
添加UICollectionViewDataSource的代理方法,使其显示数据!
1. (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.imageUrls.count;
}
2. (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
XCADCollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
cell.layer.doubleSided = NO;
[cell.adImageView sd_setImageWithURL:[NSURL URLWithString:self.imageUrls[indexPath.row]] placeholderImage:[UIImage imageNamed:@"1.jpg"]];
return cell;
}
3. 图片水平排放
4. (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(200, collectionView.frame.size.height - 100);
}
这里宽度200是图片的尺寸,高度设置collectionView的高度-100是为了防止上图中两行图片挤压的情况,所以直接让一个cell的高度占满整个容器。
- 5.
4. 顶端图片滑到中间
接下来我需要实现让第一张图片和最后一张图片都能滑到屏幕中点的位置,这应该是很常见的效果,实现起来也很简单,设置collectionview的内间距。
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
NSInteger itemCount = [self collectionView:collectionView numberOfItemsInSection:section];
NSIndexPath *firstIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
CGSize firstSize = [self collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:firstIndexPath];
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForItem:itemCount - 1 inSection:section];
CGSize lastSize = [self collectionView:collectionView layout:collectionViewLayout sizeForItemAtIndexPath:lastIndexPath];
return UIEdgeInsetsMake(0, (collectionView.bounds.size.width - firstSize.width) / 2,
0, (collectionView.bounds.size.width - lastSize.width) / 2);
}
5. 居中图片放大显示
在前面创建的 XCCollectionViewLayout类里面,有个layoutAttributesForElementsInRect的方法,功能如其名,重写下,首先需要设置放大的比例,其次要根据图片大小和间距来设定一个合适的触发放大的区域宽度,当图滑入这个区域就进行缩放
这个方法一定要加,用来刷新布局的,不然看不到滑动放大的效果
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *array = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];// 处理警告的 对数组进行深拷贝
CGRect visibleRect = (CGRect){self.collectionView.contentOffset, self.collectionView.bounds.size};
for (UICollectionViewLayoutAttributes *attributes in array) {
//如果cell在屏幕上则进行缩放
if (CGRectIntersectsRect(attributes.frame, rect)) {
attributes.alpha = 0.5;
CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;//距离中点的距离
CGFloat normalizedDistance = distance / 140;
if (ABS(distance) < 140) {
CGFloat zoom = 1 + 0.4 * (1 - ABS(normalizedDistance)); //放大渐变
attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1);
attributes.zIndex = 1;
attributes.alpha = 1.0;
}
}
}
return array;
}
下面这部分是对滑动放大图片的优化
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
CGFloat offsetAdjustment = MAXFLOAT;
//是整个collectionView在滑动偏移后的当前可见区域的中点
CGFloat centerX = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);
//所以这里对collectionView的具体尺寸不太理解,输出的是屏幕大小,但实际上宽度肯定超出屏幕的
CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
for (UICollectionViewLayoutAttributes *layoutAttr in array) {
CGFloat itemCenterX = layoutAttr.center.x;
if (ABS(itemCenterX - centerX) < ABS(offsetAdjustment)) { // 找出最小的offset 也就是最中间的item 偏移量
offsetAdjustment = itemCenterX - centerX;
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
6. 增加图片点击效果
在viewcontroller添加CollectionViewDelegate的代理方法
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
//滚动到中间
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}