UICollectionViewLayout

HJFlowLayout:

//
//  HJFlowLayout.m
//  JHCircleLayout
//
//  Created by qianfeng on 16/10/15.
//  Copyright © 2016年 qianfeng. All rights reserved.
//

#import "HJFlowLayout.h"

@implementation HJFlowLayout
/*
 *注释:
 *1.边界改变是否让旧布局无效
 *
 */
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}


/*
 *注释:第一步
 *  1.实例化时最开始调用这个方法,
 *  2.布局无效之后
 *  3.查询布局信息之前
 *  4.如果子类覆盖(重写方法),子类应该总是调用super。invalidateLayout布局无效
 *  5.在这里面一般就是写collectionView、cell。。配置信息(itemSize,间距等)
 */
-(void)prepareLayout
{
    [super prepareLayout];
    //滚动方向
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    //设置collectionView内边距
    CGFloat insert = (self.collectionView.frame.size.width - self.itemSize.width) / 2;
    
    self.sectionInset = UIEdgeInsetsMake(0, insert, 0, insert);
}






/*
 *注释:第二步
 *
 *返回滚动后推荐(proposed)停止的点(偏移量),在这里要进行处理
 */
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    //计算最终显示的边界
    CGRect rect;
    rect.origin.x = proposedContentOffset.x;
    rect.origin.y = 0;
    rect.size = self.collectionView.frame.size;
    
    // 获得所有显示区域内的布局对象
    NSArray *arr = [super layoutAttributesForElementsInRect:rect];
    // collectionView中心点的x值 、 偏移量 + 一半宽度 = 当前collectionView的中点对应着contentView的哪一个中点
    CGFloat contentCenterX = self.collectionView.frame.size.width / 2 + proposedContentOffset.x;
    //存放布局对象数组中离(上面计算的)的点最小间距的布局对象的距离
    CGFloat minDistance = MAXFLOAT;
    
    for (UICollectionViewLayoutAttributes * attr in arr) {
        
        CGFloat distance = ABS(attr.center.x - contentCenterX);
        
        minDistance = minDistance > distance ? distance : minDistance;
    }
    //处理推荐的点,达到每次都停在图片中间的效果(之所以明确是➕,因为偏移一定是负数)
    proposedContentOffset.x += minDistance;
    
    return proposedContentOffset;
}
/*
 *注释:第三步:重新布局所有子控件cell
 *
 *作用相当于layoutSubViews,最后才执行的
 */
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    //先布局super,只有流体布局才能使用
    NSArray *arr = [super layoutAttributesForElementsInRect:rect];
    
    //计算contentView中心点
    CGFloat contentCenterX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width / 2;
    
    for (UICollectionViewLayoutAttributes *attr in arr) {
        //求contentView的中心点和cell的中心点的距离[ABS:取绝对值]
        CGFloat distance = ABS(attr.center.x - contentCenterX);//比不理解。。。。。。。。。。。。。。
        //根据间距,计算缩放比例,
        CGFloat scale = 1 - distance / self.collectionView.frame.size.width;
        //设置cell的显示比例(当cell正好处于collectionView中点)
        attr.transform = CGAffineTransformMakeScale(scale, scale);
    }
    return arr;
}


@end


HJCircleLayout:


//
//  HJCircleLayout.m
//  JHCircleLayout
//
//  Created by qianfeng on 16/10/15.
//  Copyright © 2016年 qianfeng. All rights reserved.
//

#import "HJCircleLayout.h"

@interface HJCircleLayout ()
@property(nonatomic,strong)NSMutableArray * attrsArr;
@end

@implementation HJCircleLayout
-(NSMutableArray *)attrsArr
{
    if(!_attrsArr){
        _attrsArr=[[NSMutableArray alloc] init];
    }
    return _attrsArr;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}

/*
 *注释:
 *
 *
 */
-(void)prepareLayout
{
    [super prepareLayout];
    [self.attrsArr removeAllObjects];
    //计算出每组有多少个
    NSInteger  count=[self.collectionView numberOfItemsInSection:0];
    /**
     * 因为不是继承流水布局 UICollectionViewFlowLayout
     * 所以我们需要自己创建 UICollectionViewLayoutAttributes
     */
    //如果是多组的话  需要2层循环
    for (int i=0; i<count; i++) {
        //创建UICollectionViewLayoutAttributes
        NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        //这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
        UICollectionViewLayoutAttributes * attrs=[self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArr addObject:attrs];
    }
}



//获得视野范围内所有cell
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    //TODO:  特别注意 在这个方法里 可以边滑动边刷新(添加) attrs 一劳永逸 如果只需要添加一次的话  可以把这些 prepareLayout方法中去
    return self.attrsArr;
}


#pragma mark ---- 这个方法需要返回indexPath位置对应cell的布局属性
/**
 *  //TODO:  这个方法主要用于 切换布局的时候 如果不适用该方法 就不会切换布局的时候会报错
 *   reason: 'no UICollectionViewLayoutAttributes instance for -layoutAttributesForItemAtIndexPath: <NSIndexPath: 0xc000000000400016> {length = 2, path = 0 - 2}'
 */
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    //TODO: 主要是返回每个indexPath的attrs
    
    //创建UICollectionViewLayoutAttributes
    //这里需要 告诉 UICollectionViewLayoutAttributes 是哪里的attrs
    //计算出每组有多少个
    NSInteger  count=[self.collectionView numberOfItemsInSection:0];
    //角度
    CGFloat angle = 2* M_PI /count *indexPath.item;
    //设置半径
    CGFloat radius=100;
    //CollectionView的圆心的位置
    CGFloat Ox = self.collectionView.frame.size.width/2;
    CGFloat Oy = self.collectionView.frame.size.height/2;
    UICollectionViewLayoutAttributes * attrs=[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attrs.center =  CGPointMake(Ox+radius*sin(angle), Oy+radius*cos(angle));
    if (count==1) {
        attrs.size=CGSizeMake(200, 200);
    }else{
        attrs.size=CGSizeMake(50, 50);
    }
    return attrs;
}

@end



HJSquareLayout:


//
//  HJSquareLayout.m
//  JHCircleLayout
//
//  Created by qianfeng on 16/10/15.
//  Copyright © 2016年 qianfeng. All rights reserved.
//

#import "HJSquareLayout.h"

@interface HJSquareLayout ()
/** attrs的数组 */
@property(nonatomic,strong)NSMutableArray * attrsArr;
@end




@implementation HJSquareLayout
//注释:懒加载
-(NSMutableArray *)attrsArr
{
    if(!_attrsArr){
        _attrsArr=[[NSMutableArray alloc] init];
    }
    return _attrsArr;
}


- (instancetype)init
{
    self = [super init];
    if (self) {
        self.scrollDirection = UICollectionViewScrollDirectionVertical;
        self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
        
        
    }
    return self;
}



/*
 *注释:重新布局之前加载布局配置信息
 *
 *
 */
-(void)prepareLayout
{
    [super prepareLayout];
    [self.attrsArr removeAllObjects];


    //获得所有的cell的数量
    NSInteger count =[self.collectionView   numberOfItemsInSection:0];
    for (int i=0; i<count; i++) {
        NSIndexPath *  indexPath =[NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes * attrs=[self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attrsArr addObject:attrs];
    }
}


//注释:获得显示范围内所有的cell的布局属性对象
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return self.attrsArr;
}
//注释: 返回系统推荐的位置,供cell停止
-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
{
    return proposedContentOffset;
}
//注释:不设置这个,collectionView就不能滑动
-(CGSize)collectionViewContentSize
{
    
    int count =(int)[self.collectionView numberOfItemsInSection:0];
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        //获取视图对象数量
        //行数(1-1,2-1,3-1...4-2,5-2,6-2...7-3)
        int rows= (count + 2) / 3;
        //行高
        CGFloat rowH = self.collectionView.frame.size.width * 0.250;
        //行宽
        CGFloat rowW = self.collectionView.frame.size.width * 0.333;
            // 2%6余2 8%6余2:纵向(第四个,会减小高度)
//        if (count % 6 == 4) {
//            return CGSizeMake(self.collectionView.frame.size.width, rows * rowH-rowH/2);
//        }else{
//            return CGSizeMake(self.collectionView.frame.size.width, rows*rowH);
//        }
        
        return CGSizeMake(self.collectionView.frame.size.width, rowH * rows);
        
        
        
    }else{
        //列数:(1个是一列,3个也是一列)
        int columns = (count + 2) / 3;
        //行高
        CGFloat cellH = self.collectionView.frame.size.height;
        //行宽
        CGFloat cellW = self.collectionView.frame.size.width;
        //横向
        if ( count % 6 == 4) {
            return CGSizeMake(columns * cellW - cellW / 2, cellH);
        }else{
            return CGSizeMake(columns * cellW, cellH);
        }
    }
}








//返回每个指定item的布局属性对象,修改frame
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    //宽度,高度
    CGFloat width  = self.collectionView.frame.size.width * 0.333;
    CGFloat height = self.collectionView.frame.size.width * 0.250;
    
    //通过indexpath获取对象的布局属性对象
    UICollectionViewLayoutAttributes * attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    NSInteger i=indexPath.item;
    
        
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            if (i==0) {
                attr.frame = CGRectMake(0, 0, width, height);
            }else if (i==1){
                attr.frame = CGRectMake(width, 0, width, height/2);
            }else if (i==2){
                attr.frame = CGRectMake(width, height/2, width, height/2);
            }else if (i==3){
                attr.frame = CGRectMake(0, height, width, height/2);
            }else if (i==4){
                attr.frame = CGRectMake(0, height+height/2, width, height/2);
            }else if (i==5){
                attr.frame = CGRectMake(width, height, width, height);
            }else{
                UICollectionViewLayoutAttributes *lastAttrs = self.attrsArr[i-6];
                CGRect frame  = lastAttrs.frame;
                frame.origin.y+=2 * height;
                attr.frame=frame;
            }
            
//        if (i==0) {
//            attr.frame = CGRectMake(width * 0, 0, width, height);
//        }else if (i==1){
//            attr.frame = CGRectMake(width * 1, 0, width, height);
//        }else if (i==2){
//            attr.frame = CGRectMake(width * 2, 0, width, height);
//        }else{
//            UICollectionViewLayoutAttributes *nextAttr = self.attrsArr[i - 3];
//            CGRect frame = nextAttr.frame;
//            frame.origin.y += height;
//            attr.frame = frame;
//        }
        
    }else{
        
        if (i==0) {
            attr.frame = CGRectMake( 0,  0, width, height);
        }else if (i==1){
            attr.frame = CGRectMake( width, 0, width, height/2);
        }else if (i==2){
            attr.frame = CGRectMake( width, height/2, width, height/2);
        }else if (i==3){
            attr.frame = CGRectMake(width * 2, 0, width, height);
        }else if (i==4){
            attr.frame = CGRectMake(width * 3, 0, width, height/2);
        }else if (i==5){
            attr.frame = CGRectMake(width * 3, height/2, width, height/2);
        }else{
            UICollectionViewLayoutAttributes *lastAttrs = self.attrsArr[i-6];
            CGRect frame    = lastAttrs.frame;
            frame.origin.x += 4 * height;
            attr.frame=frame;
        }
        
//        if (i==0) {
//            attr.frame = CGRectMake(width * 0, 0, width, height);
//        }else if (i==1){
//            attr.frame = CGRectMake(width * 1, 0, width, height);
//        }else if (i==2){
//            attr.frame = CGRectMake(width * 2, 0, width, height);
//        }else{
//            UICollectionViewLayoutAttributes *nextAttr = self.attrsArr[i - 3];
//            CGRect frame = nextAttr.frame;
//            frame.origin.y += height;
//            attr.frame = frame;
//        }
    }
    return attr;
}

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
    return YES;
}

@end






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值