iOS开发Swift开发

自定义UICollectionViewFlowLayout处理条

2018-12-07  本文已影响94人  溜溜leesin

背景

项目中使用了一些条件选择筛选(暂且叫做条件选择器),来做筛选操作。如图:

6C212B74CB3AB48B88AA672417EAB641.png E4AF3124145BEFABD7454417CE7F99EB.png E93F16CB594A30773B4F7B3AFF7394EC.png

大概的样子是这样的。

自己在思考如果去实现这一个需求要怎么去做呢?(看我的昵称 我也很慌啊 怎么办 只能硬上了)

我想到了使用自定义UICollectionViewFlowLayout,通过三个不同的UICollectionViewFlowLayout,来控制同一个UICollectionView,来实现内容的转换。
代码如下:
.h文件:

///分类Flowlayout () ///默认4列
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface ClassFlowlayout : UICollectionViewFlowLayout

//传递的个数
@property (nonatomic, assign) NSInteger itemCount;

@end

NS_ASSUME_NONNULL_END

#import "ClassFlowlayout.h"

#define itemMargin 20
#define itemHeight 40

#define SCREEN_W  ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_H  ([UIScreen mainScreen].bounds.size.height)

**.m文件 
自定义一个FlowLayout布局类就是两个步骤:
1、设计好我们的布局配置数据 prepareLayout方法中
2、返回我们的配置数组 layoutAttributesForElementsInRect方法中**

@interface ClassFlowlayout()
{
NSMutableArray *attributeArray;
}
@end


@implementation ClassFlowlayout


-(void)prepareLayout
{
    attributeArray = [[NSMutableArray alloc]init];
    
    [super prepareLayout];
    
    //找到每一个item的frame 暂定一排最多显示4个
    CGFloat btnW = (SCREEN_W - self.sectionInset.left - self.sectionInset.right-self.minimumInteritemSpacing*3) / 4;
    
///如果是4列,那么我们需要预先设定4列的行高,这里用0.001 ,0.0011 , 0.0012做为区分。
    CGFloat cellHeight[4] = {self.sectionInset.top,self.sectionInset.top+0.001,self.sectionInset.top+0.0011,self.sectionInset.top+0.0012};
    
    
    for(int i = 0;i < _itemCount ; i++) {
        
        NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
        
        UICollectionViewLayoutAttributes *attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        
        int heightestIndex = 0;
        
        ////找到高度最低的哪一列 添加cell高度到这一列
        if (cellHeight[0] < cellHeight[1] && cellHeight[0] < cellHeight[2] && cellHeight[0] < cellHeight[3] ) {
            
            cellHeight[0] = cellHeight[0] + itemHeight + self.minimumLineSpacing;
            
            heightestIndex = 0;
            
        }
        else if (cellHeight[1] < cellHeight[0] && cellHeight[1] < cellHeight[2] && cellHeight[1] < cellHeight[3] ) {
            
            cellHeight[1] = cellHeight[1] + itemHeight + self.minimumLineSpacing;
            
            heightestIndex = 1;
        }
        
       else if (cellHeight[2] < cellHeight[0] && cellHeight[2] < cellHeight[1] && cellHeight[2] < cellHeight[3] ) {
            
            cellHeight[2] = cellHeight[2] + itemHeight + self.minimumLineSpacing;
            
            heightestIndex = 2;
        }
        
      else  if (cellHeight[3] < cellHeight[0] && cellHeight[3] < cellHeight[1] && cellHeight[3] < cellHeight[2] ) {
            
            cellHeight[3] = cellHeight[3] + itemHeight + self.minimumLineSpacing;
            
            heightestIndex = 3;
        }
        
///得到布局属性的frame
        attris.frame = CGRectMake(self.sectionInset.left + (btnW + self.minimumInteritemSpacing)*heightestIndex, cellHeight[heightestIndex] - itemHeight-self.minimumLineSpacing, btnW, itemHeight);
        
       
        
        [attributeArray addObject:attris];
    }
    
    
        ///设置itemSize来确保滑动范围的正确 这里是通过将所有的item高度平均化,计算出来的(以最高的列位标准)
        if (cellHeight[0] > cellHeight[1] && cellHeight[0] > cellHeight[2] && cellHeight[0] > cellHeight[3] ) {
            
///计算itemsize  这个公式简化过
            self.itemSize = CGSizeMake(btnW, (cellHeight[0]-self.sectionInset.top)*4/_itemCount - 3*self.minimumLineSpacing);
            
        }
          ///设置itemSize来确保滑动范围的正确 这里是通过将所有的item高度平均化,计算出来的(以最高的列位标准)
        if (cellHeight[1] > cellHeight[0] && cellHeight[1] > cellHeight[2] && cellHeight[1] > cellHeight[3] ) {
            
            self.itemSize = CGSizeMake(btnW, (cellHeight[1]-self.sectionInset.top)*4/_itemCount - 3*self.minimumLineSpacing);
            
        }
          ///设置itemSize来确保滑动范围的正确 这里是通过将所有的item高度平均化,计算出来的(以最高的列位标准)
        if (cellHeight[2] > cellHeight[0] && cellHeight[2] > cellHeight[1] && cellHeight[2] > cellHeight[3] ) {
            
            self.itemSize = CGSizeMake(btnW, (cellHeight[2]-self.sectionInset.top)*4/_itemCount - 3*self.minimumLineSpacing);
            
        }
          ///设置itemSize来确保滑动范围的正确 这里是通过将所有的item高度平均化,计算出来的(以最高的列位标准)
        if (cellHeight[3] > cellHeight[0] && cellHeight[3] > cellHeight[1] && cellHeight[3] > cellHeight[2] ) {
            
            self.itemSize = CGSizeMake(btnW, (cellHeight[3]-self.sectionInset.top)*4/_itemCount - 3*self.minimumLineSpacing);
            
        }    
}
//这个方法中返回我们的布局数组
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    return attributeArray;
}

@end

第二个样式的cell

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface SingleFlowLayout : UICollectionViewFlowLayout

@property(nonatomic,assign) NSInteger itemCount;


@end

NS_ASSUME_NONNULL_END

.m文件

#import "SingleFlowLayout.h"
#define itemHeight 60

#define itemMargin 20
#define SCREEN_W  ([UIScreen mainScreen].bounds.size.width)

@interface SingleFlowLayout()
{
    NSMutableArray *attributeArray;
}
@end

@implementation SingleFlowLayout

- (void)prepareLayout
{
    [super prepareLayout];
    
    attributeArray = [[NSMutableArray alloc]init];
    CGFloat heightArray[1] = {self.sectionInset.top};
    
    for (int i = 0; i < self.itemCount ; i++) {
        
        NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];
        
        UICollectionViewLayoutAttributes *attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        
        heightArray[0] = heightArray[0] + itemHeight + self.minimumLineSpacing;
        
        attris.frame = CGRectMake(self.sectionInset.left, heightArray[0]-itemHeight-self.minimumLineSpacing, SCREEN_W, itemHeight);
        [attributeArray addObject:attris];
        
    }
    
    self.itemSize = CGSizeMake(SCREEN_W, itemHeight);
}

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
    
    return attributeArray;
}
@end

第三个

.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MultiSectionFlowLayout : UICollectionViewFlowLayout


@property (nonatomic, assign ) NSInteger firstSectionCount;

@property (assign,  nonatomic) NSInteger secondSectionCount ;

@property (assign,  nonatomic) NSInteger thirdSectionCount ;

@end

NS_ASSUME_NONNULL_END

.m

#import "MultiSectionFlowLayout.h"
#define itemHeight 60
#define firstItemWidth   200
#define secondItemWidth  100
#define thirdItemWidth   130
@interface MultiSectionFlowLayout()
{
    NSMutableArray *attributeArray;
}
@end

@implementation MultiSectionFlowLayout

-(void)prepareLayout
{
    [super prepareLayout];
    
    attributeArray = [[NSMutableArray alloc]init];
    
    CGFloat heightArray[1] = {self.sectionInset.top};
    
    for (int i = 0;i < _firstSectionCount; i++) {
        
        NSIndexPath *index = [NSIndexPath indexPathWithIndex:i];
        
        UICollectionViewLayoutAttributes *attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        
        heightArray[0] = heightArray[0] + self.minimumLineSpacing + itemHeight;
        
        attris.frame = CGRectMake(self.sectionInset.left, heightArray[0]-itemHeight-self.minimumLineSpacing, firstItemWidth, itemHeight);
        
         NSLog(@"%@",NSStringFromCGRect(attris.frame));
        
        [attributeArray addObject:attris];
    }
    
    for (int i = 0; i < _secondSectionCount; i++) {
        
        NSIndexPath *index = [NSIndexPath indexPathWithIndex:i];
        
        UICollectionViewLayoutAttributes *atttis = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        heightArray[0] = heightArray[0] + self.minimumLineSpacing + itemHeight;
        
        atttis.frame = CGRectMake(self.sectionInset.left, heightArray[0] - itemHeight - self.minimumLineSpacing, secondItemWidth, itemHeight);
        
         NSLog(@"%@",NSStringFromCGRect(atttis.frame));
        
        [attributeArray addObject:atttis];
    }
    
    for (int i = 0; i < _thirdSectionCount; i++) {
        
        NSIndexPath *index = [NSIndexPath indexPathWithIndex:i];
        
        UICollectionViewLayoutAttributes *atttis = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];
        heightArray[0] = heightArray[0] + self.minimumLineSpacing + itemHeight;
        
        atttis.frame = CGRectMake(self.sectionInset.left, heightArray[0] - itemHeight - self.minimumLineSpacing, thirdItemWidth, itemHeight);
        
        NSLog(@"%@",NSStringFromCGRect(atttis.frame));
        
        [attributeArray addObject:atttis];
    }
///这一块有一个疑问:
   ##对于 itemSize在这样样式的layout中如何获取,求解答。   
}
@end

最后在VC中使用它们

#import "ViewController.h"
#import "ClassFlowlayout.h"
#import "SingleFlowLayout.h"
#import "MultiSectionFlowLayout.h"

#define SCREEN_W  ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_H  ([UIScreen mainScreen].bounds.size.height)
@interface ViewController () <UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout>

@property (strong, nonatomic) UICollectionView *collectionView;

@property(nonatomic,strong)ClassFlowlayout *classFlowLayout;

@property(nonatomic,strong)SingleFlowLayout *singleFlowLayout;

@property (nonatomic, strong) MultiSectionFlowLayout *multiFlowLayout;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.classFlowLayout.itemCount = 7;
    
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn1.frame = CGRectMake(0, 80, 100, 50);
    [btn1 setTitle:@"流水布局" forState:UIControlStateNormal];
    [btn1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [btn1 addTarget:self action:@selector(classBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn1];
    
    UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn2.frame = CGRectMake(200, 80, 100, 50);
    [btn2 setTitle:@"单行布局" forState:UIControlStateNormal];
    [btn2 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [btn2 addTarget:self action:@selector(singleBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn2];
    
    UIButton *btn3 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn3.frame = CGRectMake(300, 80, 100, 50);
    [btn3 setTitle:@"多行布局" forState:UIControlStateNormal];
    [btn3 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [btn3 addTarget:self action:@selector(multiBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn3];
    
    self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 150,SCREEN_W , SCREEN_H-300) collectionViewLayout:self.classFlowLayout];
    
    
    self.collectionView.backgroundColor = [UIColor whiteColor];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"1"];
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;
    [self.view addSubview:self.collectionView];
   
}


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    
    return 7;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"1" forIndexPath:indexPath];
    
    cell.backgroundColor = [UIColor colorWithRed:arc4random()%255 / 255.0 green:arc4random()%255 / 255.0 blue:arc4random()%255 / 255.0 alpha:1];
    
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%ld",(long)indexPath.row);
}



-(void)classBtnClick:(UIButton *)sender
{
    self.classFlowLayout.itemCount = 7;
    [self.collectionView setCollectionViewLayout:self.classFlowLayout animated:YES];
    
    [self.collectionView reloadData];
}

-(void)singleBtnClick:(UIButton *)sender
{
    self.singleFlowLayout.itemCount = 7;
    [self.collectionView setCollectionViewLayout:self.singleFlowLayout animated:YES];
    
    [self.collectionView reloadData];
}

-(void)multiBtnClick:(UIButton *)sender {
    
    self.multiFlowLayout.firstSectionCount = 3;
    self.multiFlowLayout.secondSectionCount = 2;
    self.multiFlowLayout.thirdSectionCount = 2;
    
    [self.collectionView setCollectionViewLayout:self.multiFlowLayout animated:YES];
    
    [self.collectionView reloadData];
}
#pragma marks --lazy load

-(ClassFlowlayout *)classFlowLayout
{
    if (!_classFlowLayout) {
        _classFlowLayout = [[ClassFlowlayout alloc] init];
    }
    return _classFlowLayout;
}

-(SingleFlowLayout *)singleFlowLayout
{
    if (!_singleFlowLayout) {
        _singleFlowLayout = [[SingleFlowLayout alloc]init];
    }
    return _singleFlowLayout;
}
-(MultiSectionFlowLayout *)multiFlowLayout
{
    if (!_multiFlowLayout) {
        _multiFlowLayout = [[MultiSectionFlowLayout alloc]init];
    }
    return _multiFlowLayout;
}
#pragma marks --- Flowlayout Delegate
##在这还是添加了UICollectionViewDelegateFlowLayout代理方法,因为在同一个分区有不同样式的cell,(本人比较菜,不知怎么在自定义的lauout中获取itemsize,有知道的大佬求告知。)
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{

    NSInteger i = indexPath.row;
    
    if(collectionViewLayout == self.multiFlowLayout) {
        
        if (i>=0 && i<self.multiFlowLayout.firstSectionCount) {
            return  CGSizeMake(SCREEN_W - 30, 60);
            
        }
        if (i >= self.multiFlowLayout.firstSectionCount && i<(self.multiFlowLayout.firstSectionCount+self.multiFlowLayout.secondSectionCount)) {
            return CGSizeMake((SCREEN_W-100)/2, 60);
        }
        if (i>=(self.multiFlowLayout.firstSectionCount+self.multiFlowLayout.secondSectionCount) && i<(self.multiFlowLayout.firstSectionCount + self.multiFlowLayout.secondSectionCount + self.multiFlowLayout.thirdSectionCount)) {
            return CGSizeMake(150, 60);
        }
    }
    return CGSizeZero;
}
@end

最后demo的效果:

未命名.gif

下载地址

上一篇下一篇

猜你喜欢

热点阅读