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, 遵守協議實現方法
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容