6

我有一个里面UICollectionView有 30 件物品UICollectionViewCell。目前有 8 个单元格在屏幕上可见,其余的几乎不可见。我能够从所有这些可见单元格中获取帧值。

我的问题是我应该怎么做才能从所有单元格中获取帧值,包括不可见的单元格。

这是我的代码。

// some code before

for (int i = 0; i < [collectionView numberOfItemsInSection:0]; i++) {
    cell = [collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
    if (!cell) {
        [collectionView performBatchUpdates:^{
            [collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0] atScrollPosition:UICollectionViewScrollPositionTop animated:NO];
            [collectionView reloadData];
        } completion:^(BOOL finished) {
            cell = [collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
            NSLog(@"- after batch update %d %@", i, NSStringFromCGRect(cell.frame));
        }];
    }
    NSLog(@"- %d %@", i, NSStringFromCGRect(cell.frame));
}

// another long code

结果是,我能够获得前 8 个单元格的正确帧。下一个单元格(不可见的单元格)有错误的框架。

这是日志:

2013-07-08 16:38:57.904 My App[71245:c07] - 0 {{2, 2}, {217, 326}}
2013-07-08 16:38:57.905 My App[71245:c07] - 1 {{231, 2}, {217, 326}}
2013-07-08 16:38:57.906 My App[71245:c07] - 2 {{460, 2}, {217, 326}}
2013-07-08 16:38:57.906 My App[71245:c07] - 3 {{689, 2}, {217, 315}}
2013-07-08 16:38:57.907 My App[71245:c07] - 4 {{689, 340}, {217, 326}}
2013-07-08 16:38:57.909 My App[71245:c07] - 5 {{2, 340}, {217, 329}}
2013-07-08 16:38:57.909 My App[71245:c07] - 6 {{231, 340}, {217, 315}}
2013-07-08 16:38:57.910 My App[71245:c07] - 7 {{460, 340}, {217, 286}}
2013-07-08 16:38:57.910 My App[71245:c07] - 8 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.911 My App[71245:c07] - 9 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.911 My App[71245:c07] - 10 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.912 My App[71245:c07] - 11 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.912 My App[71245:c07] - 12 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.913 My App[71245:c07] - 13 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.913 My App[71245:c07] - 14 {{0, 0}, {0, 0}}
2013-07-08 16:38:57.904 My App[71245:c07] - after batch update 8 {{689, 640}, {217, 326}}
2013-07-08 16:38:57.905 My App[71245:c07] - after batch update 9 {{689, 640}, {217, 326}}
2013-07-08 16:38:57.906 My App[71245:c07] - after batch update 10 {{2, 640}, {217, 326}}
2013-07-08 16:38:57.906 My App[71245:c07] - after batch update 11 {{231, 640}, {217, 315}}
2013-07-08 16:38:57.907 My App[71245:c07] - after batch update 12 {{460, 920}, {217, 326}}
2013-07-08 16:38:57.909 My App[71245:c07] - after batch update 13 {{2, 920}, {217, 329}}
2013-07-08 16:38:57.909 My App[71245:c07] - after batch update 14 {{231, 920}, {217, 315}}
4

4 回答 4

16

您不需要使单元格可见以获取它们的框架,集合视图在其管理框架(和其他布局属性)collectionViewLayout,因此您可以从中获取框架。

NSInteger numberOfCells = [self.collectionView numberOfItemsInSection:0];
UICollectionViewLayout *layout = self.collectionView.collectionViewLayout;
for (NSInteger i = 0; i < numberOfCells; i++) {
    UICollectionViewLayoutAttributes *layoutAttributes = [layout layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
    CGRect cellFrame = layoutAttributes.frame;
    NSLog(@"%i - %@", i, NSStringFromCGRect(cellFrame));
}
于 2013-07-08T10:14:03.360 回答
2

Swift 4 版本(UICollectionView 的扩展)

extension UICollectionView {

    func framesOfCells(inSection section: Int) -> [CGRect] {
        var frames: [CGRect] = []

        for item in 0..<numberOfItems(inSection: section) {
            let indexPath = IndexPath(item: item, section: section)

            if let attributes = collectionViewLayout.layoutAttributesForItem(at: indexPath) {
                let frame = attributes.frame
                frames.append(frame)
            }
        }

        return frames
    }

}
于 2019-01-17T15:11:54.963 回答
1

当我需要捕获其单元格超出可见矩形的集合视图的图像时,我遇到了类似的问题。我需要的不仅仅是所有单元格的布局信息;我需要系统来实际绘制整个集合视图。我尝试使用该scrollToItemAtIndexPath方法以编程方式扫过视图以在捕获图像之前强制绘制整个事物,但没有运气。

解决方案是,在图像捕获方法中,将集合视图框架设置为匹配整个内容大小和调用invalidate layout,这会强制视图调用整个视图中所有内容的布局属性。捕获图像后,我将集合视图恢复为其原始 UI 大小,并且效果很好:

- (UIImage *)getImageOfEntireCollectionView {

     // Store original CV frame and get content size
     CGPoint refCVOrigin = self.collectionView.frame.origin;
     CGSize refCVSize = self.collectionView.frame.size;
     CGSize contentSize = [self.collectionView.collectionViewLayout collectionViewContentSize];

     // expand CV size to match content size and redraw it
     self.collectionView.frame = CGRectMake(0, 0, contentSize.width, contentSize.height); 
     [self.layout invalidateLayout];
     [self.collectionView reloadData];

     // capture image of CV
     UIGraphicsBeginImageContext(self.collectionView.bounds.size);
     [self.collectionView.layer renderInContext:UIGraphicsGetCurrentContext()];
     UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     // restore original CV frame
     self.collectionView.frame = CGRectMake(refCVOrigin.x, refCVOrigin.y, refCVSize.width, refCVSize.height);

     return screenshot;
}
于 2014-11-12T02:40:39.080 回答
0

UICollection 视图不会为集合中的每个元素存储单元格。仅适用于可见的。当您滚动时,您只需重复使用已经不可见的那些。所以你不能得到不存在的细胞的属性。

在 MVC 中,您只需要处理数据和显示部分数据的可见单元格。所以你试图做的在概念上是错误的。

于 2013-07-08T10:03:44.247 回答