Cover Flow布局

来源:互联网 发布:apm飞控软件 编辑:程序博客网 时间:2024/05/01 06:37

Cover Flow布局

Cover Flow布局的实现,可参见教程:

  • iOS UICollectionView: The Complete Guide
  • mpospese/IntroducingCollectionViews

本文内容也是来源于此

实现过程

Cover Flow布局也是一种Flow布局,所以布局的类可直接继承自UICollectionViewFlowLayout

基本设置

1.设置scrollDirectionUICollectionViewScrollDirectionHorizontal,表示水平滚动
需要注意的是,垂直滚动和水平滚动,其行间距和item间距的不同:

这里写图片描述

2.设置minimumInteritemSpacing为一个合理的值,这样item就可以在一行显示,而不是多行显示

这里写图片描述

3.设置minimumLineSpacing为负值,这样item就叠加显示

这里写图片描述

自定义布局

自定义布局中最主要的是还是根据item的中心点距collection view中心的距离,进行3D变换

这里写图片描述

1.当某个item的中心距离visibleRect的中心点小于ACTIVE_DISTANCE(一个定义的常量)时,就需要进行3D变换,这是中间item的效果

a.只进行translate的效果
这里写图片描述

b.再添加上rotate后的效果
这里写图片描述

c.再添加上scale后的效果
这里写图片描述

2.对于距离visibleRect的中心点太大的item,主要添加2个变换

a.添加translate后的效果

这里写图片描述

b.再添加rotate后的效果

这里写图片描述

其主要代码如下:

- (void)setCellAttributes:(UICollectionViewLayoutAttributes *)attributes forVisibleRect:(CGRect)visibleRect{    // 对给定的布局attributes应用cover flow效果    // 跳过supplementary views.    if (attributes.representedElementKind) return;    // 计算距离可见区域中心的距离    CGFloat distanceFromVisibleRectToItem = CGRectGetMidX(visibleRect) - attributes.center.x;    CGFloat normalizedDistance = distanceFromVisibleRectToItem / ACTIVE_DISTANCE;    BOOL isLeft = distanceFromVisibleRectToItem > 0;    CATransform3D transform = CATransform3DIdentity;    if (fabsf(distanceFromVisibleRectToItem) < ACTIVE_DISTANCE)    {        transform = CATransform3DTranslate(CATransform3DIdentity, (isLeft? - FLOW_OFFSET : FLOW_OFFSET)*ABS(distanceFromVisibleRectToItem/TRANSLATE_DISTANCE), 0, (1 - fabsf(normalizedDistance)) * 40000 + (isLeft? 200 : 0));        // 设置透视        transform.m34 = -1/(4.6777 * self.itemSize.width);        CGFloat zoom = 1 + ZOOM_FACTOR*(1 - ABS(normalizedDistance));        transform = CATransform3DRotate(transform, (isLeft? 1 : -1) * fabsf(normalizedDistance) * 45 * M_PI / 180, 0, 1, 0);        transform = CATransform3DScale(transform, zoom, zoom, 1);        attributes.zIndex = 1;    }    else    {        transform.m34 = -1/(4.6777 * self.itemSize.width);        transform = CATransform3DTranslate(transform, isLeft? -FLOW_OFFSET : FLOW_OFFSET, 0, 0);        transform = CATransform3DRotate(transform, (isLeft? 1 : -1) * 45 * M_PI / 180, 0, 1, 0);        attributes.zIndex = 0;    }    attributes.transform3D = transform;}

还有一点就是,在滚动停止的时候,让某个item居中。
实现- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity方法即可

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{    // 返回想要collection view停止的位置    // 首先计算想要collection view停止的位置    CGFloat offsetAdjustment = MAXFLOAT;    CGFloat horizontalCenter = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);    // 使用center找到可视区域    CGRect proposedRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);    // 获取可视区域中cell的attribute    NSArray* array = [self layoutAttributesForElementsInRect:proposedRect];    // 遍历找到距离中心最近的cell    for (UICollectionViewLayoutAttributes* layoutAttributes in array)    {        // 跳过supplementary views        if (layoutAttributes.representedElementCategory != UICollectionElementCategoryCell)            continue;        // 找到最小值        CGFloat itemHorizontalCenter = layoutAttributes.center.x;        if (fabsf(itemHorizontalCenter - horizontalCenter) < fabsf(offsetAdjustment))        {            offsetAdjustment = itemHorizontalCenter - horizontalCenter;        }    }    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);}

一些问题

1.item显示的时候锯齿化严重
在实例教程中,是通过设置光栅化来解决的,需要自定义布局属性类

2.collection view中的第一个item和最后一个item不能滚动到中间
可设置collection view的section inset来解决

3.响应点击事件
上面提到的教程中,也给出了方法

原创粉丝点击