我有一个自定义 UICollectionViewLayout 类,它出现了一个奇怪的问题。上面的屏幕截图演示。由于键盘会遮挡下部字段(如果它们被编辑),我想缩短 UICollectionView 以便在键盘出现时不会被键盘遮挡。问题是我在正确的图片中得到了结果。橙色边框是承载 UICollectionView 的视图的背景,红色是 UICollectionView 的背景色。橙色背景的视图是视图控制器的根视图,并使用以下内容调整大小(自身是视图控制器)。
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