UICollectionViewFlowLayout (неправильный макет при нацеливании на iOS7 под xcode6)

У меня есть требование разместить массив фотографий, как показано на рисунке. Код для создания требуемого макета выглядит следующим образом, где UICollectionViewFlowLayout является суперклассом PhotoLayoutReordering:

@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);

iPhone5, iOS8 (правильный макет)

iPHone6, iOS8 (правильный макет)

Однако при работе с iOS7.1 макет первой ячейки неверен для iPhone4s/iPhone5. iPhone5, iOS7.1 (неправильный макет)

Я не уверен, что я что-то пропустил или есть ошибка с UICollectionViewFlowLayout? Спасибо за ваш вклад.

ОБНОВЛЕНИЕ: подкласс UICollectionViewCell имеет класс UIImageView. В раскадровке я использую autolayout, чтобы ограничить размер UIImageView, который должен быть сброшен до подкласса UICollectionViewCell со всех 4 сторон. Интерпретация ограничений в Xcode6, ориентированная на iOS7, каким-то образом неверно истолкована (по крайней мере, это предположение с моей стороны). Я решил использовать язык визуального формата, чтобы добавить ограничения, как показано ниже:

-(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 теперь соответствует размеру UICollectionViewCell со всех 4 сторон для iOS7/8. Надеюсь, это будет полезно некоторым разработчикам... Отправлен отчет об ошибке в Apple (#18415152).
ОБНОВЛЕНИЕ 07.10.14: Закрыто Apple (дубликат ошибки #18312246)


person Loozie    schedule 16.09.2014    source источник


Ответы (1)


Где вы устанавливаете размер ячеек? Похоже, вам не хватает метода делегата collectionView:layout:sizeForItemAtIndexPath:. Здесь вы устанавливаете размер отдельной ячейки.

person Sean Kladek    schedule 16.09.2014
comment
yes collectionView:layout:sizeForItemAtIndexPath: — это одно место, где делегат указывает размер отдельных ячеек. Я реализовал в делегате - person Loozie; 17.09.2014
comment
yes collectionView:layout:sizeForItemAtIndexPath: — это одно место, где делегат указывает размер отдельных ячеек. другое место layoutAttributesForElementsInRect:. однако в качестве теста я реализовал collectionView:layout:sizeForItemAtIndexPath: в объекте делегата. Результаты те же. Макет правильный при компиляции с Xcode 5, но неверен в Xcode 6, когда цель работает под управлением iOS7 (но не когда цель работает под управлением iOS8). - person Loozie; 17.09.2014
comment
Я обновил свой вопрос с решением. Кажется, что интерпретация ограничений макета в Xcode6 и Xcode5 для этого конкретного случая отличается. Я не знаю почему. Но когда я попытался ограничить использование языка визуального формата, макет ячейки работает, как и ожидалось, для iOS7 и iOS8 при компиляции в Xcode6. - person Loozie; 18.09.2014