UICollectionView:如何在委托方法中设置特定项目后获取特定项目的项目大小

时间:2012-09-25 14:27:05

标签: objective-c ios6 uicollectionview

我正在摆弄新的UICollectionView和UICollectionViewLayout类。我创建了一个自定义布局,子类化UICollectionViewFlowLayout。

我的单元格大小正在动态变化,我使用下面的委托方法设置项目大小

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

      NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
      return CGSizeMake(80, 80);
}

现在,在我的自定义UICollectionViewFlowLayout类的prepareLayout方法下,我需要访问这些大小变量,以便我可以计算如何放置它们并为layoutAttributesForItemAtIndexPath缓存它们。

但是,我似乎无法在UICollectionView或UICollectionViewFlowLayout下找到任何属性来达到我在委托方法中设置的自定义项目大小。

5 个答案:

答案 0 :(得分:13)

自己找到它。

在不遗漏UICollectionViewDelegateFlowLayout

的情况下实施自定义类
@interface SECollectionViewCustomLayout : UICollectionViewFlowLayout 
                                          <UICollectionViewDelegateFlowLayout>

然后你可以打电话

CGSize size = [self collectionView:self.collectionView 
                            layout:self 
            sizeForItemAtIndexPath:indexPath];

答案 1 :(得分:8)

查看各种UICollectionView...头文件,并观看WWDC 2012 Session 219 - Advanced Collection Views and Building Custom Layouts视频(从大约6:50开始),似乎可扩展委托模式利用动态类型来确保布局正确访问其扩展的委托方法。


简而言之......

  1. 如果使用自己的委托定义自定义布局,请在布局的头文件中定义该委托协议。
  2. 您的委托对象(通常是管理集合视图的UI(Collection)ViewController)应声明自己支持此自定义协议。
    • 如果您的布局只是UICollectionViewFlowLayout或其子类,这只是表示声明与UICollectionViewDelegateFlowLayout的一致性。
    • 如果您不想将.m布局标题放入代理人的界面,请随意在#import文件的类扩展中执行此操作。
  3. 要从布局访问委托方法,请调用集合视图的委托。
    • 使用布局的collectionView属性,将委托转换为符合所需协议的对象以说服编译器。
    • 在调用可选的委托方法之前,不要忘记像往常一样检查委托respondsToSelector:。实际上,如果您愿意,对所有方法执行此操作都没有坏处,因为类型转换意味着没有运行时保证委托甚至可以实现所需的方法。

  4. 在代码中......

    因此,如果您实现了一个自定义布局,需要委托来处理某些信息,那么您的标题可能如下所示:

    @protocol CollectionViewDelegateCustomLayout <UICollectionViewDelegate>
    - (BOOL)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout *)layout
    shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath;
    @end
    
    @interface CustomLayout : UICollectionViewLayout
    // ...
    @end
    


    你的代表声明了一致性(我在这里的实现文件中已经这样做了):

    #import "CustomLayout.h"
    
    @interface MyCollectionViewController () <CollectionViewDelegateCustomLayout>
    @end
    
    @implementation
    // ...
    - (BOOL)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout *)layout
    shouldDoSomethingMindblowingAtIndexPath:(NSIndexPath *)indexPath
    {
        return [self canDoSomethingMindblowing];
    }
    // ...
    @end
    


    在布局的实现中,您可以访问以下方法:

    BOOL blowMind;
    if ([self.collectionView.delegate respondsToSelector:@selecor(collectionView:layout:shouldDoSomethingMindblowingAtIndexPath:)]) {
        blowMind = [(id<CollectionViewDelegateCustomLayout>)self.collectionView.delegate collectionView:self.collectionView
                                                                                                 layout:self
                                                                shouldDoSomethingMindblowingAtIndexPath:indexPath];
    } else {
        // Perhaps the layout also has a property for this, if the delegate
        // doesn't support dynamic layout properties...?
        // blowMind = self.blowMind;
    }
    

    请注意,在这里进行类型转换是安全的,因为我们正在检查委托事先是否事先响应了该方法。


    证据......

    这只是猜测,但我怀疑Apple是如何管理UICollectionViewDelegateFlowLayout协议的。

    • 流布局中没有delegate属性,因此调用必须通过集合视图的委托进行。
    • UICollectionViewController不公开符合扩展流布局委托(我怀疑它是在另一个私有标头中这样做的。)
    • UICollectionView的{​​{1}}属性仅声明符合'base'delegate协议。同样,我怀疑流布局正在使用UICollectionViewDelegate的私有子类/类别,以防止需要进行类型转换。为了进一步增加这一点,Apple不鼓励在文档(Collection View Programming Guide for iOS: Creating Custom Layouts)中对UICollectionView进行子类化:
      

    避免继承UICollectionView。集合视图很少或没有自己的外观。相反,它从数据源对象中提取其所有视图,并从布局对象中提取所有与布局相关的信息。

    所以我们走了。并不复杂,但值得知道如何做到范式友好的方式。

答案 2 :(得分:4)

在GitHub上查看UICollectionView-FlowLayout。同样的想法,这只是使得访问flowLayout的扩展委托方法更加清晰。

答案 3 :(得分:0)

对于后来的读者,IOS 7具有定义它的UICollectionViewFlowLayout。

答案 4 :(得分:0)

在我的例子中,关于布局,单元格布局等的所有内容都在UIViewController的nib中定义,并为UICollectionViewCell分别定义nib。 MyCollectionViewCell包含UIImageView,其自动布局为带有填充/边距但为方形的单元格。

我需要圆形图标而不是平方但不想照顾我用于iPhone或iPad的笔尖(我有单独的笔尖用于设备和方向)。

我不想将@selector(collectionView:layout:sizeForItemAtIndexPath:)实施到我的视图控制器中。

所以,在collectionView:cellForItemAtIndexPath:内 我可以使用

CGSize size = cell.imageView.bounds.size;
cell.imageView.layer.masksToBounds = YES;
cell.imageView.layer.cornerRadius = size.height/2.0;

因为collectionView:layout:sizeForItemAtIndexPath:collectionView:cellForItemAtIndexPath:之前调用并且布局已完成。

您可以查看底部的圆形头像

enter image description here