奇妙な問題を示しているカスタム UICollectionViewLayout クラスがあります。上記のスクリーン ショットを示します。キーボードは編集された下のフィールドを覆い隠すため、UICollectionView を短くして、キーボードが表示されたときにキーボードによって覆い隠されないようにしたいと考えました。問題は、正しい画像で結果が得られることです。オレンジ色の境界線は UICollectionView をホストするビューの背景で、赤は UICollectionView の背景色です。オレンジ色の背景のビューはビュー コントローラーのルート ビューであり、次のようにサイズ変更されます (self はビュー コントローラーです)。
CGRect frame = self.view.frame;
frame.size.height -= 300;
self.view.frame = frame;
これは、ビューが希望どおりのサイズになることを示していますが、何らかの理由で UICollectionView は、下部にセルを描画する必要がないと考えています。分割する場所はほぼ一貫しているようですが、恣意的です。元のビューを下にスクロールすると、必ずしもセクション ヘッダーで分割されるとは限りません。
レイアウト クラスで、 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds に対して YES を返すと、適切に描画されますが、完全に再描画されるため、シフト/フェード処理を行うと地獄のように見えます。また、ビューのサイズを変更してもレイアウトが実際に無効になるわけではありません。同じレイアウトを使用できない理由はありません。
何が起こっているのかについてのアイデアを探しています。レイアウト コードは次のとおりです。
//
// MyLayout.h
// uicontroller
//
// Created by Guy Umbright on 8/1/12.
// Copyright (c) 2012 Guy Umbright. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "SFNativeLayout.h"
#import "SFLayoutView.h"
@class SFLayout;
@interface SFLayout : UICollectionViewLayout
@property (readonly, strong) SFNativeLayout* sfLayout;
@property (assign) BOOL deferRowsColsToCollectionView;
@property (strong) SFLayoutView* layoutView;
- (id) initWithDictionary:(NSDictionary*) dict;
- (NSInteger) numberOfSections;
- (NSInteger) numberOfItemsInSection:(NSInteger)section;
@end
//
// MyLayout.m
// uicontroller
//
// Created by Guy Umbright on 8/1/12.
// Copyright (c) 2012 Guy Umbright. All rights reserved.
//
#import "SFLayout.h"
#define ROW_HEIGHT 81 //79 with one pixel top bottom
#define HEADER_HEIGHT 30
@interface SFLayout ()
@property (strong) SFNativeLayout* sfLayout;
@property (nonatomic, strong) NSMutableArray* sectionMetrics;
@end
@implementation SFLayout
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (id) initWithDictionary:(NSDictionary*) dict
{
if (self = [super init])
{
self.sfLayout = [[SFNativeLayout alloc] initWithDictionary:dict];
}
return self;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSInteger) numberOfSections
{
if (self.deferRowsColsToCollectionView)
{
return [self.layoutView numberOfSections];
}
else
{
return self.sfLayout.sectionCount;
}
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (BOOL) sectionHasHeader:(NSInteger) section
{
BOOL result = YES;
if (self.deferRowsColsToCollectionView)
{
result = [self.layoutView sectionHasHeader:section];
}
return result;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSInteger) numberOfColumnsInSection:(NSInteger) section
{
if (self.deferRowsColsToCollectionView)
{
return [self.layoutView numberOfColumnsInSection:section];
}
else
{
SFNativeLayoutSection* layoutSection = [self.sfLayout.sections objectAtIndex:section];
NSInteger sectionColumns = layoutSection.columnCount;
return sectionColumns;
}
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSInteger) numberOfRowsInSection:(NSInteger) section
{
if (self.deferRowsColsToCollectionView)
{
return [self.layoutView numberOfRowsInSection:section];
}
else
{
SFNativeLayoutSection* layoutSection = [self.sfLayout.sections objectAtIndex:section];
return layoutSection.rowCount;
}
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (CGFloat) heightForSection:(NSInteger) sectionNdx
{
CGFloat height = 0;
if (self.deferRowsColsToCollectionView)
{
height = [self numberOfRowsInSection:sectionNdx] * ROW_HEIGHT;
if ([self sectionHasHeader:sectionNdx])
{
height += HEADER_HEIGHT;
}
}
else
{
SFNativeLayoutSection* section = [self.sfLayout.sections objectAtIndex:sectionNdx];
height += section.rowCount * ROW_HEIGHT;
if (section.includeHeader)
{
height += HEADER_HEIGHT;
}
}
return height;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (CGSize)collectionViewContentSize
{
BOOL fillSectionMetrics = NO;
CGFloat lastY = 0;
if (self.sectionMetrics == nil)
{
self.sectionMetrics = [NSMutableArray array];
fillSectionMetrics = YES;
}
CGSize sz = [self collectionView].frame.size;
CGFloat height = 0;
for (NSInteger ndx=0; ndx < [self numberOfSections]; ++ndx)
{
CGFloat sectionHeight = [self heightForSection:ndx];
height += sectionHeight;
if (fillSectionMetrics)
{
[self.sectionMetrics addObject:@{@"height":@(sectionHeight),@"startingY":@(lastY),@"endingY":@(lastY+sectionHeight)}];
lastY += sectionHeight;
}
}
sz.height = height;
return sz;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return [super shouldInvalidateLayoutForBoundsChange:newBounds];
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSArray*) attributesForSection:(NSInteger) sectionNdx inRect:(CGRect) rect
{
// NSLog(@"generate attrs for section %d", sectionNdx);
NSMutableArray* result = [NSMutableArray array];
CGRect intersect;
NSDictionary* sectionMetrics = [self.sectionMetrics objectAtIndex:sectionNdx];
SFNativeLayoutSection* layoutSection = [self.sfLayout.sections objectAtIndex:sectionNdx];
NSInteger columnCount = [self numberOfColumnsInSection:sectionNdx];
CGFloat rowStart = [[sectionMetrics valueForKey:@"startingY"] floatValue];
if ((self.layoutView.layoutDatasource != nil) || (layoutSection.includeHeader))
{
CGRect headerFrame = [self collectionView].bounds;
headerFrame.origin.y = rowStart;
headerFrame.size.height = HEADER_HEIGHT;
intersect = CGRectIntersection(rect, headerFrame);
if (!CGRectIsEmpty(intersect))
{
UICollectionViewLayoutAttributes* attr = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:@"Header"
withIndexPath:[NSIndexPath indexPathForItem:0 inSection:sectionNdx]];
attr.frame = headerFrame;
[result addObject:attr];
}
rowStart = headerFrame.origin.y + headerFrame.size.height;
}
for (int rowNdx = 0; rowNdx < [self numberOfRowsInSection:sectionNdx]; rowNdx++)
{
CGRect rowRect = [self collectionView].frame;
rowRect.size.height = ROW_HEIGHT;
rowRect.origin.y = rowStart + (rowNdx * ROW_HEIGHT);
intersect = CGRectIntersection(rect, rowRect);
if (!CGRectIsEmpty(intersect))
{
NSInteger columns = [self numberOfColumnsInSection:sectionNdx];
for (NSInteger colNdx =0; colNdx < columns; ++colNdx)
{
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:rowNdx * columnCount+colNdx inSection:sectionNdx];
CGRect frame;
frame.origin.y = rowRect.origin.y;
frame.size.height = ROW_HEIGHT;
frame.size.width = self.collectionView.frame.size.width/columnCount;
frame.origin.x = colNdx * frame.size.width;
UICollectionViewLayoutAttributes* attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.frame = frame;
[result addObject:attrs];
}
}
}
return result;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray* attributes = [NSMutableArray array];
for (NSDictionary* sectionMetric in self.sectionMetrics)
{
//can short circuit based on top of section and bottom of rect
CGRect sectionRect = [self collectionView].frame;
sectionRect.origin.y = [[sectionMetric valueForKey:@"startingY"] floatValue];
sectionRect.size.height = [[sectionMetric valueForKey:@"height"] floatValue];
CGRect intersect = CGRectIntersection(rect, sectionRect);
if (!CGRectIsEmpty(intersect))
{
NSArray* sectionAttrs = [self attributesForSection:[self.sectionMetrics indexOfObject:sectionMetric] inRect:intersect];
[attributes addObjectsFromArray:sectionAttrs];
}
}
return attributes;
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
return [super layoutAttributesForItemAtIndexPath:indexPath];
}
///////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////
- (NSInteger)numberOfItemsInSection:(NSInteger)section
{
SFNativeLayoutSection* layoutSection = [self.sfLayout.sections objectAtIndex:section];
NSInteger sectionColumns = [self numberOfColumnsInSection:section];
NSInteger sectionRows = layoutSection.rowCount; //%%%
return sectionColumns * sectionRows;
}
@end