UICollectionViewFlowLayout(在 xcode6 下定位 iOS7 时布局不正确)

Posted

技术标签:

【中文标题】UICollectionViewFlowLayout(在 xcode6 下定位 iOS7 时布局不正确)【英文标题】:UICollectionViewFlowLayout (incorrect layout when targeting iOS7 under xcode6) 【发布时间】:2014-09-16 17:15:30 【问题描述】:

我需要布置一组照片,如图所示。生成所需布局的代码如下,其中UICollectionViewFlowLayoutPhotoLayoutReordering 的超类:

@implementation PhotoLayoutReordering

-(instancetype) initWithCoder:(NSCoder *)aDecoder 
self = [super initWithCoder:aDecoder];
if (self) 
    ;// additional set up here
    self.scrollDirection = UICollectionViewScrollDirectionVertical;

return self;


-(CGSize) calculateSecondaryCellSizeAndMargin 
CGSize cellSize;
cellSize.width = self.collectionView.frame.size.width/NUMBER_OF_COLUMNS;
cellSize.width = cellSize.width - 2*SPACE_BETWEEN_CELLS;
CGSize secondaryCellSize = CGSizeMake(cellSize.width,cellSize.width);
//    NSLog(@"cell width:%1.0f\t cell height:%1.0f\t   margin:%1.0f\n",secondaryCellSize.width,secondaryCellSize.height,_spaceBetweenCells);
//    NSLog(@"number of cells are: %d",(int)[self.collectionView numberOfItemsInSection:0]);
return secondaryCellSize;


-(CGSize) calculatePrimaryCellSize 
CGFloat width;
CGSize secondaryCellSize = [self calculateSecondaryCellSizeAndMargin];
width = (NUMBER_OF_COLUMNS-1)* secondaryCellSize.width + NUMBER_OF_COLUMNS*SPACE_BETWEEN_CELLS;
return CGSizeMake(width, width);


-(UICollectionViewLayoutAttributes*) layoutAttributesAtIndexPath:(NSIndexPath*) indexPath 
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
return attributes;


#pragma mark - UICollectionViewLayout overridden methods
-(CGSize) collectionViewContentSize 
CGSize primaryCellSize = [self calculatePrimaryCellSize];
CGFloat heightForPrimaryCell = primaryCellSize.height + NUMBER_OF_COLUMNS*SPACE_BETWEEN_CELLS;
if ([self.collectionView numberOfItemsInSection:0] > NUMBER_OF_COLUMNS) 
    NSUInteger nubmerOfSecondaryRows = [self.collectionView numberOfItemsInSection:0]/NUMBER_OF_COLUMNS;
    CGFloat heightForSecondaryCells = nubmerOfSecondaryRows * [self calculateSecondaryCellSizeAndMargin].height;
    heightForPrimaryCell += heightForSecondaryCells;

//    NSLog(@"height of collectionview %1.0f",heightForPrimaryCell);
return CGSizeMake(self.collectionView.frame.size.width, heightForPrimaryCell);


-(NSArray*) layoutAttributesForElementsInRect:(CGRect)rect 
NSLog(@"layoutAttributesForElementsInRect");
NSMutableArray *attributesInRect = [NSMutableArray array];
NSInteger numberOfCell = [self.collectionView numberOfItemsInSection:0];
for (int index=0; index < numberOfCell; index++) 
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0];
    [attributesInRect addObject:[self calculateLayouAttributes:indexPath]];


for (UICollectionViewLayoutAttributes *attribute in attributesInRect) 
    NSLog(@"%@",attribute);

return attributesInRect;


-(UICollectionViewLayoutAttributes*) layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 
NSLog(@"layoutAttributesForItemAtIndexPath");
return [self calculateLayouAttributes:indexPath];

我正在使用 Xcode6。使用 ios8 运行模拟器时,iPhone4s、iPhone5、iPhone6 和 iPhone6 Plus 的布局是正确的。下图-(NSArray*) layoutAttributesForElementsInRect:返回的属性数组是正确的。

2014-09-16 09:47:30.600 Postlets[3606:212466]    layoutAttributesForElementsInRect 
2014-09-16 09:47:30.600    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1880>    index path: (<NSIndexPath: 0x7afb0dc0> length = 2, path = 0 - 0);    frame = (2 2; 236 236);  
2014-09-16 09:47:30.600    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1950>    index path: (<NSIndexPath: 0x7afb1900> length = 2, path = 0 - 1);    frame = (242 2; 76 76);  
2014-09-16 09:47:30.600    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb19d0>    index path: (<NSIndexPath: 0x7afb1910> length = 2, path = 0 - 2);    frame = (242 82; 76 76);  
2014-09-16 09:47:30.600    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1a60>    index path: (<NSIndexPath: 0x7afb1a50> length = 2, path = 0 - 3);    frame = (242 162; 76 76);  
2014-09-16 09:47:30.600    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1af0>    index path: (<NSIndexPath: 0x7afb1ae0> length = 2, path = 0 - 4);    frame = (2 242; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1b90>    index path: (<NSIndexPath: 0x7afb0be0> length = 2, path = 0 - 5);    frame = (82 242; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1c20>    index path: (<NSIndexPath: 0x7afb1c10> length = 2, path = 0 - 6);    frame = (162 242; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1ca0>    index path: (<NSIndexPath: 0x7afb1920> length = 2, path = 0 - 7);    frame = (242 242; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1d20>    index path: (<NSIndexPath: 0x7afb1930> length = 2, path = 0 - 8);    frame = (2 322; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1de0>    index path: (<NSIndexPath: 0x7afb1940> length = 2, path = 0 - 9);    frame = (82 322; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1e70>    index path: (<NSIndexPath: 0x7afb1e60> length = 2, path = 0 - 10);    frame = (162 322; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1f00>    index path: (<NSIndexPath: 0x7afb1ef0> length = 2, path = 0 - 11);    frame = (242 322; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb1f90>    index path: (<NSIndexPath: 0x7afb1f80> length = 2, path = 0 - 12);    frame = (2 402; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb2020>    index path: (<NSIndexPath: 0x7afb2010> length = 2, path = 0 - 13);    frame = (82 402; 76 76);  
2014-09-16 09:47:30.601    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb20b0>    index path: (<NSIndexPath: 0x7afb20a0> length = 2, path = 0 - 14);    frame = (162 402; 76 76);  
2014-09-16 09:47:30.602    Postlets[3606:212466] <UICollectionViewLayoutAttributes: 0x7afb2140>    index path: (<NSIndexPath: 0x7afb2130> length = 2, path = 0 - 15);    frame = (242 402; 76 76);

但是,在 iOS7.1 上运行时,第一个单元格的布局对于 iPhone4s/iPhone5 是不正确的。

我不确定我是否忽略了某些内容,或者 UICollectionViewFlowLayout 是否存在错误?感谢您的意见。

更新:UICollectionViewCell 的子类有一个UIImageView。在情节提要中,我使用自动布局来限制 UIImageView 的大小,使其在所有 4 个面上刷新到 UICollectionViewCell 的子类。针对 iOS7 的 Xcode6 中对约束的解释在某种程度上被误解了(至少这是我的猜测。)我决定使用 Visual Format Language 添加约束,如下所示:

-(void) layoutViews 
_imageView = [[RemoteImageView alloc] init]; // this is a subclass of UIImageView
_imageView.translatesAutoresizingMaskIntoConstraints = NO;
_imageView.contentMode = UIViewContentModeScaleAspectFill;
_imageView.clipsToBounds = YES;

[self addSubview:_imageView];
NSDictionary *views = NSDictionaryOfVariableBindings(_imageView);//,spinner);
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_imageView]|" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_imageView]|" options:0 metrics:nil views:views]];

UIImageView 现在大小合适,可以在 iOS7/8 的所有 4 个面上与UICollectionViewCell 齐平。希望这对那里的一些开发人员有用... 向 Apple 提交错误报告 (#18415152)。 2014 年 10 月 7 日更新:由 Apple 关闭(与错误 #18312246 重复)

【问题讨论】:

【参考方案1】:

你在哪里设置单元格的大小?看起来您缺少 collectionView:layout:sizeForItemAtIndexPath: 委托方法。您可以在此处设置单个单元格的大小。

【讨论】:

yes collectionView:layout:sizeForItemAtIndexPath: 是代理指定单个单元格大小的地方。我在委托中实现 yes collectionView:layout:sizeForItemAtIndexPath: 是代理指定单个单元格大小的地方。另一个地方是layoutAttributesForElementsInRect:。但是,作为测试,我在委托对象中实现了collectionView:layout:sizeForItemAtIndexPath:。结果是一样的 -- 使用 Xcode 5 编译时布局是正确的,但在目标运行 iOS7 时布局在 Xcode 6 中不正确(但在目标运行 iOS8 时不正确)。 我用“a”解决方案更新了我的问题。对于这种特殊情况,Xcode6Xcode5 中布局约束的解释似乎不同。我不知道为什么。但是当我尝试使用 Visual Format Language 进行约束时,在Xcode6 中编译时,单元格布局在 iOS7 和 iOS8 中按预期工作。

以上是关于UICollectionViewFlowLayout(在 xcode6 下定位 iOS7 时布局不正确)的主要内容,如果未能解决你的问题,请参考以下文章