14

我正在摆弄新的 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 下找到任何属性来达到我在委托方法中设置的自定义项目大小。

4

6 回答 6

13

自己找到的。

像不省略一样实现自定义类UICollectionViewDelegateFlowLayout

@interface SECollectionViewCustomLayout : UICollectionViewFlowLayout 
                                          <UICollectionViewDelegateFlowLayout>

然后你可以打电话

CGSize size = [self collectionView:self.collectionView 
                            layout:self 
            sizeForItemAtIndexPath:indexPath];
于 2012-09-25T15:50:45.550 回答
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:在调用可选委托方法之前,不要忘记像往常一样检查委托。事实上,如果你愿意,对所有方法都这样做并没有什么坏处,因为类型转换意味着没有运行时保证委托甚至会实现所需的方法。


在代码中...

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

@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不公开符合扩展流布局委托(我怀疑它在另一个私有标头中这样做)。
  • UICollectionViewdelegate属性仅声明符合“基本”UICollectionViewDelegate协议。同样,我怀疑UICollectionView流布局是否使用了私有子类/类别来防止需要进行类型转换。为了进一步强调这一点,Apple 不鼓励UICollectionView在文档中进行子类化(iOS 的集合视图编程指南:创建自定义布局):

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

所以我们开始了。并不复杂,但值得知道如何以范式友好的方式进行操作。

于 2014-02-06T07:41:29.970 回答
8

有一个快速版本:

self.collectionView(self.collectionView, layout: self.collectionView.collectionViewLayout, sizeForItemAtIndexPath: indexPath)
于 2015-07-15T10:38:22.453 回答
4

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

于 2012-10-05T22:09:11.063 回答
0

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

于 2015-04-25T05:25:01.707 回答
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:和布局完成。

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

在此处输入图像描述

于 2017-06-11T23:20:33.793 回答