自定义UICollectionViewLayout:获取某个单元格的大小

时间:2014-03-21 22:38:26

标签: ios objective-c uicollectionview uicollectionviewcell uicollectionviewlayout

我根据客户的设计规范为客户构建自定义UICollectionViewLayout,以实现他们想要的外观和流程。我遇到的问题涉及我定位的单元格大小。

单元格可能具有不同的尺寸,而我所采用的布局样式需要特定的间距要求,以便单元格不会相互重叠,这意味着在重载{ {1}}在布局中,我希望查看项目大小,以便在计算中正确设置和使用。

我遇到的问题是-layoutAttributesForItemAtIndexPath:似乎依赖于此方法来设置单元格的大小,因为在我设置属性之前,我使用任何方法从a获取大小单元格将始终生成UICollectionView

这是我必须要设计的东西吗?故事板中单元格的大小是不可访问的(至少我目前所知的方法)所以除了使用特定的宽度/高度之外,我还没有能够解决这个问题。 (仅适用于两个可能的单元格之一)来测试和编写布局代码。

最终:如何获取CGSizeZeroUICollectionViewCell的大小以用于计算?

修改

我尝试过以下方法:

UICollectionViewLayout

1 个答案:

答案 0 :(得分:6)

我从未找到避免在代码中重复大小计算的方法。这就是我通常做的事情:

获取布局中的大小:

布局可以与其集合视图对话以查找大小(以及最小项目间距等内容)。您可以在-prepareLayout-layoutAttributesForItemAtIndexPath:

中执行以下操作
if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]) {
    id<UICollectionViewDelegateFlowLayout> delegate = (id<UICollectionViewDelegateFlowLayout>) self.collectionView.delegate;
    size = [delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
}
else {
    size = self.itemSize;
}

现在,您的集合视图委托只需要能够响应collectionView:layout:sizeForItemAtIndexPath:,即使没有自定义布局类也是如此。

首先计算尺寸:

有时提供正确的尺寸有点麻烦。没有神奇的方法来获得单元格的大小而没有实际实例化并放置它,所以我总是自己编写代码。我的大多数集合视图单元都有一个类方法:

+ (CGSize)sizeWithItem:(id<MyDisplayableItem>)item;

当我需要一个单元格所需的大小时,我从我的集合视图委托中调用它:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    Note* note = self.notes[indexPath.item];
    CGSize result = [CSDetailNoteCell sizeWithNote:note];
    // or [MyCell sizeWithItem:myItem andMyOtherItem:somethingElse]
    return result;
}

不幸的是,+sizeWithItem:方法并非免费提供,但至少它将大小计算封装在Cell类中。我倾向于在类中存储一个常量,表示永远不会改变的事物的大小(填充,也许是图像)。然后,我将固定大小与需要动态计算的内容相结合,以找到最终大小。动态内容通常包括对NSString的-boundingRectWithSize:options:attributes:context:等的一些调用。

样本量计算:

此示例使用宽度始终为320的单元格,但我认为足以获得该点。这是来自CSDetailNoteCell.m的代码。

static CGFloat const CSDetailNoteCellWidth = 320.f;
static CGFloat const CSDetailNoteCellHeightConstant =
        10 + // top padding
        16 + // date label height
        0 + // padding from date label to textview
        8 + // textview top padding
        8 + // textview bottom padding
        22 // bottom padding
;

...

+ (CGFloat)textWidth {
    return CSDetailNoteCellTextViewWidth - 10; // internal textview padding
}

+ (CGSize)sizeWithNote:(CSNote *)note {
    CGFloat textHeight = [self _textHeightWithText:note.text];
    CGSize result = CGSizeMake(CSDetailNoteCellWidth, CSDetailNoteCellHeightConstant + textHeight);
    return result;
}

+ (CGFloat)_textHeightWithText:(NSString*)text {
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];

    CGSize maxSize = CGSizeMake(CSDetailNoteCell.textWidth, CGFLOAT_MAX);
    NSDictionary* attributes = @{NSFontAttributeName: CSDetailNoteCell.font, NSParagraphStyleAttributeName: paragraphStyle};
    CGRect boundingBox = [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];
    CGFloat textHeight = ceilf(boundingBox.size.height);
    return textHeight;
}
相关问题