zoukankan      html  css  js  c++  java
  • 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;
    }
     
     
  • 相关阅读:
    noi 2011 noi嘉年华 动态规划
    最小乘积生成树
    noi 2009 二叉查找树 动态规划
    noi 2010 超级钢琴 划分树
    noi 2011 阿狸的打字机 AC自动机
    noi 2009 变换序列 贪心
    poj 3659 Cell Phone Network 动态规划
    noi 2010 航空管制 贪心
    IDEA14下配置SVN
    在SpringMVC框架下建立Web项目时web.xml到底该写些什么呢?
  • 原文地址:https://www.cnblogs.com/Walking-Jin/p/5211151.html
Copyright © 2011-2022 走看看