• UICollectionView


    ⼀、什么是集合视图
     
    在iOS6.0之后,苹果推出了⼀个新的继承于UIScrollView的⼀个视 图,UICollectionView,也被称之为集合视图。和UITableView共同作为 在开发中⾮常常⽤的两个视图,常常作为项⽬的主界⾯出现。
     
    ⼆、创建UICollectionView
     
    UICollection的实现跟tableView不⼀样的地⽅在于Item的布局 稍微复杂⼀点,需要⽤UICollectionViewLayout类来描述视图的 布局。我们在项⽬中常⽤的是系统提供的 UICollectionViewFlowLayout类,也可以⾃定义 UICollectionViewLayout。
     
    //创建一个布局对象,采用系统布局类UICollectionViewFlowLayout
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];

        layout.itemSize = CGSizeMake(120, 200);
        layout.minimumLineSpacing = 0;
        layout.minimumInteritemSpacing = 7.5;
        layout.sectionInset = UIEdgeInsetsMake(50, 0, 0, 0);
      
        //设置最小的行间距
        layout.minimumLineSpacing = 20;
       
        //设置item与item之间的间距
        layout.minimumInteritemSpacing = 10;
       
        //设置集合视图的分区间隔
        layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
     
        //设置集合视图的滑动方向
        layout.scrollDirection = UICollectionViewScrollDirectionVertical;
       
        CGFloat totalWidth = self.view.frame.size.width;

        //设置每一个item的尺寸大小
        layout.itemSize = CGSizeMake((totalWidth - 40) / 3, 80);
       
        layout.headerReferenceSize = CGSizeMake(totalWidth, 40);
       
        //集合视图的创建,必须指定布局,如果没有布局,显示不了任何东西。
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
       
        collectionView.dataSource = self;//数据源
        collectionView.delegate = self;//代理
       
    //    collectionView.backgroundColor = [UIColor redColor];
       
        //集合视图如果想要显示内容,必须将cell进行注册
        [collectionView registerClass:[YourCollectionViewCell class] forCellWithReuseIdentifier:kStr];
       
        //集合视图如果想要分区头视图显示,必须注册增广视图
        [collectionView registerClass:[YourCollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
       
        [self.view addSubview:collectionView];
     
    UICollectionView和UITableView⼀样,也需要遵守两个代理协 议:UICollectionViewDelegate和UICollectionViewDataSource。
    当遵守了这两个代理协议之后,UICollectionView才可以正常 的显⽰。
    @interface ViewController : UIViewController<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
    @end
     
     
    UICollectionView和UITableView⼀样有两个必须实现的代理⽅法。
    返回多少个Item; 
    指定每个item的样式。
     
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
        return 6;
    }

    // The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
       
        YourCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kStr forIndexPath:indexPath];
       
        cell.contentView.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 255.0 green:arc4random() % 256 / 255.0 blue:arc4random() % 256 / 255.0 alpha:1.0];
        cell.numberLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];
       
        return cell;
    }
     
    选择实现的代理方法
     
    //设置分区个数 返回有多少个分区
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
        return 10;
    }
     
    //item点击之后触发的方法
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
        NSLog(@"%ld %ld",indexPath.section, indexPath.row);
    }
     
    UICollectionView不能像UITableView⼀样直接指定头部和尾部视 图,需要注册使⽤,最⼤的好处是添加了重⽤机制。
    //返回增广视图,也就是集合视图的头视图或者尾视图
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
        YourCollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath];
        view.headerLabel.text = [NSString stringWithFormat:@"当前分区为:%ld",indexPath.section];
       
        view.backgroundColor = [UIColor yellowColor];
        return view;
    }
     
    三、布局协议
     
    布局协议:UICollectionViewDelegateFlowLayout,它是对 UICollectionViewDelegate的扩展
     
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
        return CGSizeMake((kWidth - 40) / 3, 100);
    }

    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
        return UIEdgeInsetsMake(0, 0, 0, 0);
    }

    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
        return 20;
    }


    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
        return 20;
    }

    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
        return CGSizeMake(kWidth, 40);
    }
     
    四、⾃定义UICollectionViewLayout
     
    系统给我们提供的 UICollectionViewFlowLayout布局类不 能实现瀑布流的效果,如果我们想实现 瀑布流的效果,需要⾃定义⼀个 UICollectionViewLayout类,实现瀑布 流效果。
     
    我们需要⼀个图⽚⼤⼩和图⽚地址的Json数据,和SDWebImage 图⽚加载的第三⽅⼯具。
     
    第一步:创建⼀个继承于UICollectionViewLayout的类,声明⼀个代理协议,并声明协议⽅法。
     
    @protocol WaterFlowLayoutDelegate <NSObject>

    //关键方法,此方法的作用是返回每一个item的size大小
    - (CGSize)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;

    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;

    - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(WaterFlowLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;

    @end
     
    @interface WaterFlowLayout : UICollectionViewLayout
     
    @property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;
     
    第二步:
     
    在接⼝⽂件中声明需要提供给外界使⽤的属性。
     
    //瀑布流一共多少列
    @property (nonatomic, assign) NSUInteger numberOfColumn;
    // item的⼤⼩
    @property (nonatomic, assign) CGSize itemSize;
    // 内边距
    @property (nonatomic, assign) UIEdgeInsets sectionInsets;
    // item的间距
    @property (nonatomic, assign) CGFloat insertItemSpacing;
    // 代理⼈
    @property (nonatomic, assign) id<WaterFlowLayoutDelegate>delegate;
     
    @end
     
    第三步:
     
    在实现⽂件中声明⼀些不需要提供给外界的⽅法和属性。
     
    //  WaterFlowLayout.m
     
    @interface WaterFlowLayout ()

    // 获取item的总数量
    @property (nonatomic, assign) NSUInteger numberOfItems;
    //存放每一列的高度
    @property (nonatomic, retain) NSMutableArray *columnHeightsArray;
    //存放 每一个item的 属性 包含 frame以及下标(x,y,w,h)
    @property (nonatomic, retain) NSMutableArray *attributesArray;
    //保存每个Item的X值
    @property (nonatomic, assign) CGFloat detalX;
    //保存每个Item的Y值
    @property (nonatomic, assign) CGFloat detalY;
    //记录最短列
    @property (nonatomic, assign) NSInteger shortestIndex;
    //获取最长列的索引
    - (NSInteger)p_indexForLongestColumn;
    //获取最短列的索引
    - (NSInteger)p_indexForShortestColumn;

    @end
     
    第四步:
     
    数据源的懒加载⽅法
     
    //懒加载
    - (NSMutableArray *)columnHeightsArray {
        if (!_columnHeightsArray) {
            self.columnHeightsArray = [NSMutableArray array];
        }
        return _columnHeightsArray;
    }
    - (NSMutableArray *)attributesArray {
        if (!_attributesArray) {
            self.attributesArray = [NSMutableArray array];
        }
        return _attributesArray;
    }
     
    第五步:
     
    //获取最小高度的方法
    - (CGFloat)minHeight
    {
        CGFloat min = 100000;
        for (NSNumber *height in _columnHeightsArray) {
            CGFloat h = [height floatValue];
            if (min > h) {
                min = h;
            }
        }
        return min;
    }

    //获取最大值
    - (CGFloat)maxHeight
    {
        CGFloat max = 0;
        for (NSNumber *height in _columnHeightsArray) {
            CGFloat h = [height floatValue];
            if (max < h) {
                max = h;
            }
        }
        return max;
    }
     
     
    第六步:
     
    获取索引
     
    //获取最短列索引
    - (NSUInteger) p_indexForShortestColumn
    {
        //记录索引
        NSUInteger index = 0;
        for (int i = 0; i < [_columnHeightsArray count]; i ++) {
            //获取当前高度
            CGFloat height = [_columnHeightsArray[i] floatValue];
            if (height == [self minHeight]) {
                index = i;
                return index;
            }
        }
        return index;
    }
     
    //获取最长列的索引
    - (NSInteger)p_indexForLongestColumn {
        //记录哪一列最长
        NSInteger longestIndex = 0;
        for (int i = 0; self.numberOfColumn; i ++) {
            //获取高度
            CGFloat currentHeight = [self.columnHeightsArray[i] floatValue];
            if (currentHeight == [self maxHeight]) {
                longestIndex = i;
            }
        }
        return longestIndex;
    }
     
    第七步:
     
    //重写父类的布局方法
    - (void)prepareLayout
    {
        [super prepareLayout];
       
        _attributesArray = [[NSMutableArray alloc] init];
       
        _columnHeightsArray = [[NSMutableArray alloc] initWithCapacity:self.numberOfColumn];
       
        //给列高数组里面的对象赋初值
        for (int i = 0; i < self.numberOfColumn; i ++) {
            [_columnHeightsArray addObject:@0.0];
        }
       
        CGFloat totalWidth = self.collectionView.frame.size.width;
       
        //创建 每个item frame中的x、y
        CGFloat x = 0;
        CGFloat y = 0;
       
        NSUInteger itemCount = [self.collectionView numberOfItemsInSection:0];
       
        for (int i = 0; i < itemCount; i ++) {
            //得到集合视图中 列间隙的个数
            NSUInteger numberOfSpace = self.numberOfColumn - 1;
           
            //代理对象执行代理方法,得到 item之间的间隙大小
            CGFloat spaceWidth = [_delegate collectionView:self.collectionView layout:self minimumInteritemSpacingForSectionAtIndex:0];
           
            //求每列的宽度,也就是每个item的width
            CGFloat width = (totalWidth - spaceWidth * numberOfSpace) / self.numberOfColumn;
           
           
            //获取每一个itemSize的大小
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
           
            //数据中原始图片大小
            CGSize imageSize = [_delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
       
            //通过 约分公式得到固定宽之后的高度是多少
            CGFloat height = width * imageSize.height / imageSize.width;
           
           
            UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
           
            //记录每一个item的大小和位置
            attribute.frame = CGRectMake(x, y, width, height);
           
            //数组保存每个item的位置信息
            [_attributesArray addObject:attribute];
           
            NSLog(@"item = %d",i);
            NSLog(@"x = %.2f y = %.2f width = %.2f height = %.2f",x,y,width,height);
           
            //求列高最小的那一列的下标
            NSUInteger minHeightIndex = [self indexOfMinHeight];
           
            //求出最小列的高度
            CGFloat minHeight = [_columnHeightsArray[minHeightIndex] floatValue];
           
            //求出行高
            CGFloat lineHeight = [_delegate collectionView:self.collectionView layout:self minimumLineSpacingForSectionAtIndex:0];
           
            //上一次总的列高 加上 行高 加上新加上的item的height,才是现在这一列的总高度
            //minHeight为最小列现在的高度
            //lineHeight为行间距
            //height为新加的item的高
            _columnHeightsArray[minHeightIndex] = [NSNumber numberWithFloat:minHeight + lineHeight + height];
           
            //重新算最小列高的下标
            minHeightIndex = [self indexOfMinHeight];
           
            //算下一次新加的item的x和y值
            x = (spaceWidth + width) * minHeightIndex;
           
            y = [self minHeight];
        }
    }

    //重写这个方法,可以返回集合视图的总高度
    - (CGSize)collectionViewContentSize
    {
        return CGSizeMake(self.collectionView.frame.size.width, [self maxHeight]);
    }

    //这个方法不写 集合视图显示不出来,这个方法是将保存的每个item的信息告诉集合视图,进行显示。
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        return _attributesArray;
    }
     
     
  • 相关阅读:
    告诉自己的十大忠告
    深度学习框架
    深度学习-Caffe编译测试的小总结
    深度学习-Windows平台下的Caffe编译教程
    C#中使用多款LevelDB.Net封装测试性能
    LevelDB初体验测试
    机器学习-分类器-Adaboost原理
    机器学习-分类器-级联分类器训练(Train CascadeClassifier )
    C# Directory.GetFiles()获取多个类型格式的文件
    部分Android或IOS手机拍照后照片被旋转的问题
  • 原文地址:https://www.cnblogs.com/Walking-Jin/p/5211151.html
Copyright © 2020-2023  润新知