collectionView 实现画廊效果

效果

collectionView 实现画廊效果_第1张图片
效果.png

标题是collectionView,但其实这篇文章说的是自定义FlowLayout的事

大家都知道collectionView关于元素的事情,更多是于布局决定的。

比如滚动方向,元素间距,元素尺寸,布局的组间距,布局的行间距(这些都决定了元素的位置)。

如果要实现画廊效果只需要关心三个方法

/**
 *  当bounds发生改变(滚动就是改变了bounds,改变了可视区)的时候是否允许刷新布局。
 *
 *  @param newBounds 
 *
 *  @return 默认返会NO
 */
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
   return YES;
}
/**
 *  返回区域内的cell,这个方法做根据cell距离中心点 来缩放
 *
 *  @param rect 区域
 *
 *  @return 区域内的cell
 */
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    //bounds的改变就是可视范围的改变, 那么我们去拿可视范围内的cell
    NSArray *attrs = [super layoutAttributesForElementsInRect:self.collectionView.bounds];
    
    //计算每一个cell与中心点的距离, 并通过cell与中心点距离的改变来缩放cell
    for (UICollectionViewLayoutAttributes *attr in attrs) {
        CGFloat delta = fabs((attr.center.x - self.collectionView.contentOffset.x) - self.collectionView.frame.size.width * 0.5);
        
        CGFloat scale = 1 - (delta / self.collectionView.bounds.size.width * 0.5) * 0.55;
        
        attr.transform = CGAffineTransformMakeScale(scale, scale);
    }
    
    return attrs;
}
/**
 *  计算最终的偏移量, 在这个方法里做判断最小距离自动滚动到中间效果
 *
 *  @param proposedContentOffset 预计偏移
 *  @param velocity              速率
 *
 *  @return 最终偏移
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {
    
    CGFloat collectionW = self.collectionView.bounds.size.width;
    CGFloat collectionH = self.collectionView.bounds.size.height;
    
//    1确定最终的滚动位置
    CGPoint targetP = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity];
//    2利用滚动位置去拿当前显示的所有元素
    CGRect rect = CGRectMake(targetP.x, 0, collectionW, collectionH);
    NSArray *attrs = [super layoutAttributesForElementsInRect:rect];
    
//    3获取所有滚动元素距离中心点的最小值
    CGFloat minDelta = MAXFLOAT;
    for (UICollectionViewLayoutAttributes *attr in attrs) {
        CGFloat delta = attr.center.x - targetP.x - collectionW * 0.5;
        
        if (fabs(delta) < fabs(minDelta))
            minDelta = delta;
    }
    
//    4用最终的偏移量加最小值 形成自动滑动的效果
    targetP.x += minDelta;
    if (targetP.x < 0)
        targetP.x = 0;
        
    return targetP;
}
bounds
bounds的origin是可以改变的,取决于有没有可视范围外的可滚动区域。
scrollView的滚动是通过可视范围的改变(bounds)来实现滚动的。

想要实现这个效果的朋友直接自定义FlowLayout,重写以上三个方法即可。

你可能感兴趣的:(collectionView 实现画廊效果)