何时以及如何调用 collectionView:viewForSupplementaryElementOfKind:atIndexPath:?

Posted

技术标签:

【中文标题】何时以及如何调用 collectionView:viewForSupplementaryElementOfKind:atIndexPath:?【英文标题】:When and how is collectionView:viewForSupplementaryElementOfKind:atIndexPath: called? 【发布时间】:2013-06-16 10:00:21 【问题描述】:

我正在尝试使用 UICollectionView 和自定义布局来实现类似于原生日历应用的时间线视图。而且我是新手。

这就是我的问题所在。

我正在使用装饰视图来实现那些背景网格线,并尝试使用补充视图来制作时间标签(靠近网格线),并将使用 Cell 来制作事件但还没有那么远。

但是在做这些事件之前,我发现当我运行它时,所有的补充视图都不起作用,不管我有没有单元格。我发现我的 collectionView:viewForSupplementaryElementOfKind:atIndexPath: 方法未被调用

所以我想知道如何以及何时调用此方法?什么可能导致我的情况没有被调用?

其实,把那些时间标签做成补充视图好不好?我不确定,因为即使没有事件(部分中没有单元格/项目),我也确实需要它们可见。

这是我的代码:

视图控制器

- (void)viewDidLoad

    [super viewDidLoad];
    self.collectionView.backgroundColor = [UIColor whiteColor];

    [self.collectionView registerClass:TodayCellKindTask.class forCellWithReuseIdentifier:CellKindTaskIdentifier];
    [self.collectionView registerClass:TodayTimelineTimeHeader.class forSupplementaryViewOfKind:TimelineKindTimeHeader withReuseIdentifier:TimelineTimeHeaderIdentifier];
    [self.timelineViewLayout registerClass:TodayTimelineTileWhole.class forDecorationViewOfKind:TimelineKindTileWholeHour];
    [self.timelineViewLayout registerClass:TodayTimelineTileHalf.class forDecorationViewOfKind:TimelineKindTileHalfHour];


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 
    return 5;


- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
    TodayCellKindTask *cellTask = [collectionView dequeueReusableCellWithReuseIdentifier:CellKindTaskIdentifier forIndexPath:indexPath];
    return cellTask;


- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath 
    NSLog(@"viewForSupplementaryElementOfKind");
    TodayTimelineTimeHeader *timeHeader = [self.collectionView dequeueReusableSupplementaryViewOfKind:TimelineKindTimeHeader withReuseIdentifier:TimelineTimeHeaderIdentifier forIndexPath:indexPath];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *today = [NSDate date];
    NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:today];
    [comps setHour:indexPath.item];
    timeHeader.time = [calendar dateFromComponents:comps];
    return timeHeader;

自定义布局

// in prepareLayout
NSMutableDictionary *timeHeaderAttributes = [NSMutableDictionary dictionary];
CGSize headerSize = [TodayTimelineTimeHeader defaultSize];
CGFloat headerOffsetY = (tileSize.height - headerSize.height) / 2;
for (NSInteger hour = 24; hour >= 0; hour--) 
    NSIndexPath *timeHeaderIndexPath = [NSIndexPath indexPathForItem:hour inSection:0];
    UICollectionViewLayoutAttributes *currentTimeHeaderAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:TimelineKindTimeHeader withIndexPath:timeHeaderIndexPath];
    CGFloat headerPosY = hour * 2 * tileSize.height + headerOffsetY;
    currentTimeHeaderAttributes.frame = CGRectMake(TimeHeaderPosX, headerPosY, headerSize.width, headerSize.height);
    timeHeaderAttributes[timeHeaderIndexPath] = currentTimeHeaderAttributes;

self.timelineTileAttributes[TimelineKindTimeHeader] = timeHeaderAttributes;


// layoutAttributesForSupplementaryViewOfKind
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath 
    return self.timelineTileAttributes[kind][indexPath];


// layoutAttributesForElementsInRect
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 
    NSMutableArray *allAttributes = [NSMutableArray arrayWithCapacity:self.timelineTileAttributes.count];
    [self.timelineTileAttributes enumerateKeysAndObjectsUsingBlock:^(NSString *elementIdentifier,
                                                                    NSDictionary *elementsInfo,
                                                                    BOOL *stop) 
       [elementsInfo enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath,
                                                        UICollectionViewLayoutAttributes *attributes,
                                                        BOOL *stop) 
           if (CGRectIntersectsRect(rect, attributes.frame)) 
               [allAttributes addObject:attributes];
           
       ];
    ];
    return allAttributes;


// collectionViewContentSize
- (CGSize)collectionViewContentSize 
    CGSize tileSize = [TodayTimelineTileWhole defaultSize];
    CGFloat contentHeight = tileSize.height * self.numberOfTiles;
    return CGSizeMake(tileSize.width, contentHeight);

我尽量不在这里发布所有代码,因为那会很多,但如果您需要了解其他人,请告诉我。

感谢任何提示!

松树

【问题讨论】:

您能否发布您的代码,尤其是您如何实现 collectionView:viewForSupplementaryElementOfKind:atIndexPath 方法?也许你还需要设置流布局的 headerReferenceSize。 @verbumdei 代码添加在那里,但我没有使用我正在编写的流布局,所以这里没有 headerReferenceSize。感谢您的跟进! 【参考方案1】:

所以,这个问题解决了,原因是我的愚蠢错误,将这些视图的位置 x 设置在屏幕之外,因此没有调用该方法。没有别的了。

我通过在prepareLayout中注销每个视图的框架找到了这个原因,并发现x位置错误。我从视网膜设计中得到了这个位置,所以......

我使用了补充视图,它可以正常工作。

我的教训:别担心,冷静下来。这可以节省您犯错的时间。

【讨论】:

以上是关于何时以及如何调用 collectionView:viewForSupplementaryElementOfKind:atIndexPath:?的主要内容,如果未能解决你的问题,请参考以下文章

在 NextJS s-s-r 流程中何时以及如何调用 React 生命周期方法?

何时以及为何调用 updateConstraints?

我应该何时调用 StateHasChanged 以及 Blazor 何时自动拦截某些更改?

何时使用 socket.io ?以及何时使用简单的 Http 调用? [复制]

IOS 查看代表以及何时调用它们

你能解释一下何时以及为啥在 hive 中调用 mapreduce