D14:UICollectionView(单分组, 多分组, 模拟穷游App的折扣页面)

UICollectionView网格视图

网格视图是能够显示多列的列表视图, 弥补了UITableView不方便实现多列的缺点, 在iOS6之后才有这个控件
Inheritance
NSObject
UIResponder
UIView
UIScrollView
UICollectionView

UICollectionViewFlowLayout: 确定网格视图的布局

上下左右的间距: sectionInset(left, top, bottom, right)
每一个Cell的大小: itemSize(width, height)
横向Cell之间的间距: minimumInteritemSpacing
纵向Cell之间的间距: minimumLineSpacing


目录

一.单分组的网格视图

  1. 系统的Cell
  2. 代码自定制的Cell
  3. xib自定义Cell

二.多分组的网格视图

  1. Header
  2. Footer

三.实现穷游App的折扣界面

  1. 创建模型类, 导入MyDownloader类(用于从网上下载数据)
  2. 解析下载到的JSON数据, 创建数据源(此处下载到的是JSON数据, 以后也可能需要下载解析XML数据)
  3. 自定义Cell
  4. 常规流程: 创建CollectionView, 遵守协议实现方法

一.单分组的网格视图

  1. 使用系统的Cell
    1. 创建数据源

    2. 创建UICollectionView对象

      1. 指定初始化方法

         // 第一个参数: 位置    
         // 第二个参数: 布局对象
         - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;  
         UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 20, kWidthOfScreen, kHeightOfScreen - 20) collectionViewLayout:layout];  
        
      2. 布局对象 UICollectionViewLayout

        // 布局对象是一个UICollectionViewLayout类型的对象
        // 由于我们是规则的布局, 可以直接使用UICollectionViewFlowLayout对象
        // UICollectionViewFlowLayout继承于UICollectionViewLayout
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        // 1. 上下左右的间距
        /*
         UIEdgeInsets:<#CGFloat top#>(上面的间距), <#CGFloat left#>(左边), <#CGFloat bottom#>(底部), <#CGFloat right#>(右边)
         */
        layout.sectionInset = UIEdgeInsetsMake(5, 5, 5, 5);
        // 2. cell的大小
        layout.itemSize = CGSizeMake(180, 100);
        // 3. 横向间距
        layout.minimumInteritemSpacing = 5;
        // 4. 纵向间距
        layout.minimumLineSpacing = 10;
        
      3. 设置UICollectionView对象的属性

         // 设置代理
         collectionView.delegate = self;
         // 设置数据源代理
         collectionView.dataSource = self;
         // 设置白色背景
         collectionView.backgroundColor = [UIColor whiteColor];
         
         // 注册cell的类型
         // 以代码的方式注册Cell的类型, 表示创建Cell的时候用这个类型来创建
         /*
          第一个参数: Cell的类型
          第二个参数: 重用标志
          */
         [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kCellReuseId];
         
         // 添加到父视图上
         [self.view addSubview:collectionView];  
        
    3. 遵守协议, 实现协议方法
      - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

       // 返回每一个Cell的对象
       // UICollectionView上面的每一个Cell是UICollectionViewCell类型(或子类型)的对象
       // UICollectionViewCell也是一个视图
       - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
       {
           // 从重用队列里面获取
           /*
            第一个参数: 重用id
            第二个参数: cell的位置
            */
           
           // UITableView      -> NSIndexPath:section row
           // UICollectionView -> NSIndexPath:section item
           UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellReuseId forIndexPath:indexPath];
       
           // 不需要再创建, 从dequeueReusableCellWithReuseIdentifier方法李米娜一定能够获取到
           // 设置背景颜色
           cell.backgroundColor = [UIColor grayColor];
           
           // 显示文字
           UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, 180, 40)];
           label.textAlignment = NSTextAlignmentCenter;
           // 获取文字
           NSString *str = self.dataArray[indexPath.item];
           label.text = str;
           // 添加到父视图
           [cell.contentView addSubview:label];
           
           return cell;
       }  
      
    4. 因为每次都是新添一个UILabel, 所以会有滑动出现重影的问题(其实是UILabel的重叠)

       // 解决方法, 在为cell设新的UILabel前移除之前的子视图
          for (UIView *sub in cell.contentView.subviews) {
              [sub removeFromSuperview];
          }
      
  2. 代码自定制的Cell
    1. 创建数据源
    2. 创建UICollectionView对象
      1. 指定初始化方法
        - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
      2. 布局对象 UICollectionViewLayout
      3. 设置UICollectionView对象的属性
    3. 遵守协议, 实现协议方法
    4. 因为自建的cell的控件是其属性, 所以每次重新设置cell的控件的属性不会发生重影的问题
  3. Xib定制的Cell
    1. 创建数据源

    2. 创建UICollectionView对象

      1. 指定初始化方法
        - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;

      2. 布局对象 UICollectionViewLayout (可以使用UICollectionViewDelegateFlowLayout代理来设置)

        Getting the Size of Items
        – collectionView:layout:sizeForItemAtIndexPath:
        Getting the Section Spacing
        – collectionView:layout:insetForSectionAtIndex:
        – collectionView:layout:minimumLineSpacingForSectionAtIndex:
        – collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
        Getting the Header and Footer Sizes
        – collectionView:layout:referenceSizeForHeaderInSection:
        – collectionView:layout:referenceSizeForFooterInSection:
        
      3. 设置UICollectionView对象的属性

      4. 注册cell的类型

         // 注册cell(xib)
         // 第一个参数: xib的对象(UINib类型)
         // 第二个参数: 重用标志
         UINib *nib = [UINib nibWithNibName:@"DataCell" bundle:nil];
         [collectionView registerNib:nib forCellWithReuseIdentifier:kCellReuseId];
        
    3. 遵守协议, 实现协议方法
      - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
      {
      // 从重用列表中获取
      DataCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellReuseId forIndexPath:indexPath];
      ..........................................................................
      }

代码自定制的cell和xib的区别:注册Cell方法的不同
- (void)registerClass:(Class)cellClass forCellReuseIdentifier:(NSString *)identifier
- (void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier


二.多分组的网格视图

  1. Header
    1. 新建headerView类, 继承自UICollectionReusableView

    2. 注册header

       /*
        第一个参数:header视图对象的类型
        第二个参数:区分是header还是后面的footer
        // UICollectionElementKindSectionHeader表示header类型
        第三个参数:重用标志
        */
       [_collectionView registerClass:[HeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:KHeaderReuseId];
      
    3. 在布局对象的代理协议方法中设置header的大小
      - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
      {
      return CGSizeMake(375, 40);
      }

    4. 返回header对象 UICollectionViewDataSource的协议方法(也可以用来返回footer对象)
      - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
      {
      if (kind == UICollectionElementKindSectionHeader) {
      // header类型

               // 从重用队列里面获取
               HeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:KHeaderReuseId forIndexPath:indexPath];
               
               // 设置背景颜色
               header.backgroundColor = [UIColor redColor];
               // 显示数据
               header.titleLabel.text = [NSString stringWithFormat:@"第%c组", (int)(indexPath.section + 'A')];
               return header;
       
           } else if (kind == UICollectionElementKindSectionFooter) {
               // footer
               
               // 从重用队列里面获取
               FooterView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:KFooterReuseId forIndexPath:indexPath];
               
               footer.backgroundColor = [UIColor purpleColor];
               // 显示数据
               footer.titleLabel.text = [NSString stringWithFormat:@"第%c组结束", (int)(indexPath.section + 'A')];
               return footer;
           }
           return nil;
       }  
      
  2. Footer
    1. 新建FooterView类, 继承自UICollectionReusableView

    2. 注册footer

       [_collectionView registerClass:[FooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:KFooterReuseId];
      
    3. 在布局对象的代理协议方法中设置footer的大小
      - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
      {
      return CGSizeMake(375, 40);
      }

    4. 返回footer对象 UICollectionViewDataSource的协议方法(也可以用来返回header对象)


三.实现穷游App的折扣界面

  1. 创建模型类, 导入MyDownloader类(用于从网上下载数据)
     // 下载数据
     - (void)downloadData
     {
         // 创建myDownloader对象
         MyDownloader *downloader = [[MyDownloader alloc] init];
         // 设置代理
         downloader.delegate = self;
         // 下载数据
         [downloader downloadWithUrlString:kUrl];
     }
     
     // MyDownloader代理方法
     // 下载失败
     - (void)downloaderFail:(NSError *)error downloader:(MyDownloader *)downloader
     {
         NSLog(@"%@", error);
     }
    
  2. 解析下载到的JSON数据, 创建数据源(此处下载到的是JSON数据, 以后也可能下载XML数据)
     // 下载成功
     - (void)downloaderFinish:(MyDownloader *)downloader
     {
         // 下载回来的数据在downloader.receiveData这个属性里
         // JSON解析
         id result = [NSJSONSerialization JSONObjectWithData:downloader.receiveData options:NSJSONReadingMutableContainers error:nil];
         if ([result isKindOfClass:[NSDictionary class]]) {
             // 如果是字典 按照字典来操作
             NSDictionary *dict = result;
             NSArray *array = dict[@"data"];
             for (NSDictionary *dataDict in array) {
                 // NSLog(@"%@", dataDict);
                 
                 // 创建模型对象
                 DataModel *model = [[DataModel alloc] init];
                 [model setValuesForKeysWithDictionary:dataDict];
                 
                 // 添加到数组中
                 [self.dataArray addObject:model];
             }
             // 刷新网格视图
             [_collectionView reloadData];
         }
     }
    
    • 因为上方使用KVC方法来创建模型对象, 所以我们要在模型类的.m文件中重写方法
      - (void)setValue:(id)value forUndefinedKey:(NSString *)key
      {
      }
  3. 自定义Cell
    • DataCell.m
      - (void)config:(DataModel *)model
      {
      // 图片
      [self.picImageView sd_setImageWithURL:[NSURL URLWithString:model.pic]];

            // 价格
            self.priceLabel.text = model.buy_price;
            
            // 名字
            self.nameLabel.text = model.title;
            self.nameLabel.numberOfLines = 2;
            self.nameLabel.font = [UIFont boldSystemFontOfSize:18];
            
            // 时间
            self.timeLabel.text = model.end_date;
            
            // 折扣
            self.discountLabel.text = model.lastminute_des;
        }
      
      • 因为我们的图片是从根据一个网址的字符串去网上下载的,所以我们导入了另一个第三方库UIImageView+WebCache 用于下载网上图片
        - (void)sd_setImageWithURL:(NSURL *)url
        {
        [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil];
        }
  4. 常规流程: 创建CollectionView, 遵守协议实现方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容