【问题标题】:UICollectionViewCell using prototype sizesUICollectionViewCell 使用原型尺寸
【发布时间】:2014-03-17 23:00:08
【问题描述】:

我有一个 UICollectionView,其中包含三个不同的原型单元格,每个单元格都通过 Storyboard 设置不同的高度。在运行时,Collection View 使用自己的单元格大小,忽略我的 Storyboard 的。

我目前正在使用 collectionView:layout:sizeForItemAtIndexPath: 和几个条件来直接设置每个 CGSize。

有没有更好的方法来设置单元格大小?我似乎无法检索每个单元格的 Storyboard 大小,而且 CGSizeMake 似乎太硬编码并且不是很灵活。

【问题讨论】:

    标签: ios objective-c uicollectionview uicollectionviewcell


    【解决方案1】:

    目前似乎没有简单的方法:

    • 从 Storyboard 中获取 UICollectionViewCell 原型单元大小运行时。
    • 只需在一处管理原型单元的大小(而不必在故事板单元原型中输入它们并实施sizeForItemAtIndexPath)。

    建议的方法here(用于UITableViews)不起作用,因为在sizeForItemAtIndexPath 中使用dequeueReusableCellWithReuseIdentifier 会导致无限循环。

    但是,我设法通过以下方式做到了这一点

    1. 在所有 Storyboard 中的每个 UICollectionView 原型单元格中添加一个唯一的(在每个故事板中的所有 UICollectionViewCells 中)重用标识符。

    2. 使用从所有 Storyboard 中提取 UICollectionViewCell 帧大小的脚本,将 Run script 构建阶段添加到您的项目中。

      output=${PROJECT_DIR}/StoryboardPrototypeCellSizes.h
      printf "@{" > $output
      
      for storyboard in $(find ${PROJECT_DIR} -name "*.storyboard")
      do
          echo "Scanning storyboard $storyboard..."
          delimiter=
          for line in $(xpath $storyboard "//collectionViewCell/@reuseIdentifier[string-length()>0] | //collectionViewCell/rect" 2>&-)
          do
              case $line in
                  reuseIdentifier*)
                      reuseIdentifier=$(sed 's/[^"]*"\([^"]*\)".*/\1/' <<< $line)
                      ;;
                  width*)
                      if [ -n "$reuseIdentifier" ]; then
                          width=$(sed 's/[^"]*"\([^"]*\)".*/\1/' <<< $line)
                      fi
                      ;;
                  height*)
                      if [ -n "$reuseIdentifier" ]; then
                          height=$(sed 's/[^"]*"\([^"]*\)".*/\1/' <<< $line)
                      fi
                      ;;
              esac
      
              if [ -n "$reuseIdentifier" ] && [ -n "$width" ] && [ -n "$height" ]; then
                  printf "$delimiter@\"$reuseIdentifier\" : [NSValue valueWithCGSize:CGSizeMake($width, $height)]" >> $output
                  unset reuseIdentifier
                  unset width
                  unset height
                  delimiter=,\\n
              fi
          done
      done
      
      printf "};\n" >> $output
      

      这将创建一个名为 StoryboardPrototypeCellSizes.h 的头文件,其中包含以下示例内容:

      @{@"TodayCell" : [NSValue valueWithCGSize:CGSizeMake(320, 80)],
      @"SpecialDayCell" : [NSValue valueWithCGSize:CGSizeMake(320, 42)],
      @"NameDayCell" : [NSValue valueWithCGSize:CGSizeMake(320, 30)]};
      
    3. 添加一个辅助方法以在控制您的 UICollectionView 的视图控制器中返回 UICollectionViewCell 重用标识符:

      - (NSString *)cellReuseIdentifierAtIndexPath:(NSIndexPath *)indexPath
      {
          switch (indexPath.item) {
              case 0: return @"TodayCell";
              case 1: return @"SpecialDayCell";
              case 2: return @"NameDayCell";
          }
          return nil;
      }
      
    4. 确保在cellForItemAtIndexPath 中使用相同的重用标识符:

      - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
      {
          UICollectionViewCell *cell =
              [collectionView dequeueReusableCellWithReuseIdentifier:
                  [self cellReuseIdentifierAtIndexPath:indexPath]
                  forIndexPath:indexPath];
          ...
      
    5. 终于实现sizeForItemAtIndexPath

      - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
      {
          NSDictionary *storyboardPrototypeCellSizes =
      #import "StoryboardPrototypeCellSizes.h"
      
           return [(NSValue *)storyboardPrototypeCellSizes[
                   [self cellReuseIdentifierAtIndexPath:indexPath]
                  ] CGSizeValue];
      }
      

    此解决方案允许您在 Storyboard(s) 中仅定义一次 UICollectionViewCell 原型单元大小,并且在运行时也不会执行任何不符合 App Store 的操作。

    ****Edit:**** 您还可以通过添加另一个具有相同内容的脚本并将“collectionViewCell”替换为“collectionReusableView”并将头文件重命名为例如 StoryboardReusableViewSizes.h 来获取 UICollectionReusableView 大小

    【讨论】:

    • 海拉作弊,但是...很棒。
    • 对于那些在 iOS 8 发布后来到这里的人,解决这个问题的方法是使用自调整大小的单元格。通过自动布局单元格,使其宽度/高度根据内容大小而变化,可以让 CollectionView 调整单元格的大小以适应其内容。
    • '这里提出的方法(用于 UITableViews)不起作用,因为在 sizeForItemAtIndexPath 中使用 dequeueReusableCellWithReuseIdentifier 会导致无限循环。这个真的帮了我很大的忙,因为我不知道为什么我的应用程序总是崩溃。
    【解决方案2】:

    没有更好的方法来设置单元格大小。单元格大小在 UICollectionView 中的多个位置使用 - 用于定位,用于滚动指示器。例如,如果用户滚动收集具有数千个小单元格的集合,尽快接收它们是非常重要的。因此,创建单元格并询问其大小不是一种选择。您必须实现 collectionView:layout:sizeForItemAtIndexPath: 并且它应该可以快速运行。

    【讨论】:

      【解决方案3】:

      您是否在UICollectionView 中使用流式布局?如果是,您可以使用UICollectionViewDelegateFlowLayout 协议的sizeForItemAtIndexPath 方法来提供单元格的大小。如果您在应用程序中使用 OSS 组件没有问题,可以使用RFQuiltLayout 来实现此目的。

      【讨论】:

      • 就像我在问题本身中提到的那样,我目前正在使用 sizeForItemAtIndexPath。另外,我可能错了,但 RFQuiltLayout 不会将集合分成小块吗?我认为它不适合与几个不成比例的可变高度单元格一起使用(例如,一个是 90 点,另一个是 131 点,最后一个是 78 点高)。
      • 您提到UICollectionView 中有三个不同的原型单元格,您是否探索过使用 Autolayout 布置它们的子视图? Obc.io 在UICollectionView 布局上有一个nice article。在 UICollectionView 中使用 Autolayout 的示例是 here。根据我的经验,最好使用UICollectionView的布局对象来控制每个单元格的大小和位置,同时使用Autolayout来布局子视图?
      • 我们越来越接近我想要的结果了!这是一篇很棒的文章。我正在尝试完全按照这些思路进行操作,但我正在寻找一种方法来使用我在 Storyboard Collection View 中实例化的 Storyboard 单元,而不是在外部创建一个 XIB 并以编程方式注册它们。有什么想法吗?编辑:我尝试通过标签号实例化它们,但这似乎不起作用。另外,我不能在 sizeForItem 中出列。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-14
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多