UICollectionView实现轮播图

1,374 阅读2分钟

先来看效果

滑动到当前cell时,显示原尺寸大小;两边的按比例缩小;滑动时变大,最大为原尺寸大小。

思路

直接续承UICollectionViewFlowLayout,实现以下方法:

/**
 *  collectionView的显示范围发生改变的时候,调用下面这个方法是否重新刷新
 *
 *  @return 是否重新刷新
 */
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}
/**
 *  布局的初始化操作
 */
- (void)prepareLayout
{
    [super prepareLayout];
    // 设置为水平滚动
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
}
/**
 *  设置cell的显示大小
 *
 *  @param rect 范围
 *
 *  @return 返回所有元素的布局
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    // 获取计算好的布局属性
    NSArray *arr = [[NSArray alloc]initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
    for (int i = 0; i < arr.count; i ++) {
        UICollectionViewLayoutAttributes *att = arr[i];
        //算比例
        //拿到每个item的位置  算出itemCenterX  和collectionCenterX 的一个距离
        CGFloat distance = ABS(att.center.x - self.collectionView.frame.size.width * 0.5 - self.collectionView.contentOffset.x);
        CGFloat scale = 0.75;
        CGFloat w = (self.collectionView.frame.size.width) * 0.5;
        if (distance >= w) {
            scale = scale;
        }else{
            scale = scale +  (1- distance / w ) * 0.25;
        }
        att.transform = CGAffineTransformMakeScale(1.0, scale);
    }
    return arr;
}
//滑动完成后,会来到此方法 - 线性滑动
//proposedContentOffset  最后停止的 contentOffset
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    //proposedContentOffset滑动之后最后停的位置
    CGRect  rect;
    rect.origin = proposedContentOffset;
    rect.size = self.collectionView.frame.size;
    //获取停止时,显示的cell的frame
    NSArray<__kindof UICollectionViewLayoutAttributes *> *tempArray = [[NSArray alloc]initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
    CGFloat  gap = 1000;
    CGFloat  a = 0;
    for (int i = 0; i < tempArray.count; i++) {
        //判断和中心的距离,得到最小的那个
        int edge = [tempArray[i] center].x - proposedContentOffset.x - self.collectionView.frame.size.width * 0.5;
        if (gap > ABS(edge)) {
            gap =  ABS(edge);
            a = edge;
        }
    }
    CGPoint  point  = CGPointMake(proposedContentOffset.x + a , proposedContentOffset.y);
    
    return point;
}

使用

初始化

-(UICollectionView *)collectionView{
    if (_collectionView == nil) {
        ELDiscoveryCarouselLayout * layout = [[ELDiscoveryCarouselLayout alloc] init];
        
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
        //UIScrollViewDecelerationRateFast
        _collectionView.decelerationRate = 0.9938;
        _collectionView.delegate = self;
        _collectionView.dataSource = self;
        _collectionView.backgroundColor = ELBlueColor;
//        _collectionView.pagingEnabled = YES;
        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:collectionCellId];
    }
    return _collectionView;
}
  • 不要设置pagingEnabled,否则targetContentOffsetForProposedContentOffset:withScrollingVelocity:将不起作用;
  • decelerationRatetypedef CGFloat UIScrollViewDecelerationRate NS_TYPED_ENUM;类型的数据,它有两个值UIScrollViewDecelerationRateNormalUIScrollViewDecelerationRateFast
UIScrollViewDecelerationRate数值
UIScrollViewDecelerationRateNormal0.998
UIScrollViewDecelerationRateFast0.98999999999999999(0.99)

所以我们也可以直接给decelerationRate赋值,范围是0.0~1.0,值越小,滑动越快,也就达到了pagingEnabled的效果了。

实现代理

#pragma mark ============ collectionview代理 ==============
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return 13;
}


-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:collectionCellId forIndexPath:indexPath];
    cell.contentView.backgroundColor = ELRedColor;
    
    return cell;
}

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    return CGSizeMake(ScreenW-40, SH(130));
}
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
    return UIEdgeInsetsMake(10, 20, 10, 20);
}
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
    return 10;
}

-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
    return 10;
}

完成