Note that there are some explanatory texts on larger screens.

plurals
  1. POStrange "splitting" with custom UICollectionViewLayout upon resizing
    primarykey
    data
    text
    <p><img src="https://i.stack.imgur.com/zaHhT.png" alt="before"> <img src="https://i.stack.imgur.com/b2GbN.png" alt="after"></p> <p>I have a custom UICollectionViewLayout class that is exhibiting a weird problem. Screen shots above demonstrate. As the keyboard would obscure the lower fields is they were edited, I wanted to shorten the UICollectionView so that it would not be obscured by the keyboard when it came up. The problem is that I get the result in the right picture. The orange border is the background of the view hosting the UICollectionView, the red is the background color of the UICollectionView. The view with the orange background is the root view for the view controller and is resized with the following (self being the view controller).</p> <pre><code> CGRect frame = self.view.frame; frame.size.height -= 300; self.view.frame = frame; </code></pre> <p>It indicates that the view gets sized as desired, but for some reason the UICollectionView thinks it does not need to draw the cells in the lower portion. The place where it splits seem to be about consistent but arbitrary. If the original view is scrolled down it does not necessarily split at the section header.</p> <p>In the layout class, if I return YES for - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds it draws properly but does full redraw so it looks like hell as it does that shifting/fadey thing. And resizing the view does not really invalidate the layout, there is no reason the same layout cannot be used.</p> <p>Looking for any ideas as to what might be going on. The layout code follows:</p> <pre><code>// // MyLayout.h // uicontroller // // Created by Guy Umbright on 8/1/12. // Copyright (c) 2012 Guy Umbright. All rights reserved. // #import &lt;UIKit/UIKit.h&gt; #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 &lt; [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 &lt; [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 &lt; 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 </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload