iOS开发之CollectionViewFlowLayout实现LOL皮肤选择动画

WzxJiang

编辑:Bison
投稿:WzxJiang

"之前做瀑布流的时候接触过CollectionViewFlowLayout,但是一直没弄明白,所以昨天乘着有空钻一下这个知识点。"


1

这篇文章就不讲解CollectionView怎么创建啊什么的问题,这些问题可以直接看我最下面放的完整代码,注释很详细,这篇文章就直接讲我在这个Demo里怎么用CollectionViewFlowLayout的。

首先创建一个CollectionViewFlowLayout子类:


#import <UIKit/UIKit.h>

@interface WZXLOLCardLayout : UICollectionViewFlowLayout

@end

我们需要重写CollectionViewFlowLayout以下几个方法:

//这个用来传基本的数据 每次刷新第一步就是走这个方法
- (void)prepareLayout
//允许更新位置 你要是静态的话就不用重写了
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)oldBounds
//最重要的方法 返回当前矩形内所有的UICollectionViewLayoutAttributes 
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect

可能有人会对当前矩形不太理解,可以简单理解为collectionview在你当前屏幕的位置.

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity

这个方法有些类似于scrollview的scrollViewWillEndDragging.

具体如下

#define GiveMeHeight(HEIGTH) (HEIGTH*[UIScreen mainScreen].bounds.size.height/736.0)
#define GiveMeWidth(WIDTH) (WIDTH*[UIScreen mainScreen].bounds.size.width/414.0)

//第一个要重写的方法 设置基本的大小
- (void)prepareLayout
{
    //cell大小
    self.itemSize = CGSizeMake(GiveMeWidth(300),GiveMeHeight(500));
    //滑动方向
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    //组间四个方位间距
    self.sectionInset = UIEdgeInsetsMake(200, 50.0, 200, 50.0);
    //列间距
    self.minimumLineSpacing = 0.0;
}
//允许更新位置
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)oldBounds
{
    return YES;
}
//最大旋转角度
#define rotate 35.0*M_PI/180.0
//返回一个rect位置下所有cell的位置数组
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
    //得到所有的UICollectionViewLayoutAttributes
    NSArray* array = [super layoutAttributesForElementsInRect:rect];

    CGRect visibleRect;
    visibleRect.origin = self.collectionView.contentOffset;
    visibleRect.size = self.collectionView.bounds.size;

    for (UICollectionViewLayoutAttributes* attributes in array) {

        //cell中心离collectionview中心的位移
        //CGRectGetMidX表示得到一个frame中心点的X坐标
        CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;

        //CGRectIntersectsRect 判断两个矩形是否相交
        //这里判断当前这个cell在不在rect矩形里
        if (CGRectIntersectsRect(attributes.frame, rect))
        {
            CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;

        //ABS 绝对值
        //如果位移小于一个过程所需的位移
        if (ABS(distance) < ACTIVE_DISTANCE)
        {
            //normalizedDistance 当前位移比上完成一个过程所需位移 得到不完全过程的旋转角度
            CGFloat zoom = rotate*normalizedDistance;
            CATransform3D transfrom = CATransform3DIdentity;
            transfrom.m34 = 1.0 / 600;
            transfrom = CATransform3DRotate(transfrom, -zoom, 0.0f, 1.0f, 0.0f);
            attributes.transform3D = transfrom;
            attributes.zIndex = 1;

        }
        else
        {
            CATransform3D transfrom = CATransform3DIdentity;
            transfrom.m34 = 1.0 / 600;
            //向右滑
            if (distance>0)
            {
                transfrom = CATransform3DRotate(transfrom, -rotate, 0.0f, 1.0f, 0.0f);

            }
            //向左滑
            else
            {
                transfrom = CATransform3DRotate(transfrom, rotate, 0.0f, 1.0f, 0.0f);
            }

                attributes.transform3D = transfrom;
                attributes.zIndex = 1;
            }

        }
    }
    return array;
}

//类似于scrollview的scrollViewWillEndDragging
//proposedContentOffset是没有对齐到网格时本来应该停下的位置
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat offsetAdjustment = MAXFLOAT;

    //CGRectGetWidth: 返回矩形的宽度
    CGFloat horizontalCenter = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);

    //当前rect
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

    NSArray* array = [super layoutAttributesForElementsInRect:targetRect];
    //对当前屏幕中的UICollectionViewLayoutAttributes逐个与屏幕中心进行比较,找出最接近中心的一个
    for (UICollectionViewLayoutAttributes* layoutAttributes in array)
    {
        CGFloat itemHorizontalCenter = layoutAttributes.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) < ABS(offsetAdjustment))
        {
            //与中心的位移差
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
    }
    //返回修改后停下的位置
    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}

接下来就只要在创建CollectionView的时候使用就行了:

WZXLOLCardLayout * flowLayout = [[WZXLOLCardLayout alloc]init];
_cardView = ({
    UICollectionView * collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:flowLayout];

    collectionView.delegate   = self;
    collectionView.dataSource = self;

    //提前注册
    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];

    collectionView;
});

[self.view addSubview:_cardView];

完整代码

GitHub


博主app上线啦,快点此来围观吧

更多经验请点击

好文推荐:Bison眼中的iOS开发多线程是这样的(一)


分享文章