I'm having a weird issue, when using a collection view with dynamic sizes, this issue doesn't happens while using fixed sizes.
After a reload the first cell of each section disappears, but only if they are out of the screen. After a few tests I realize that the cell didn't disappear, but its hidden bellow the section header.
Do you have any idea what is causing this?
Collection without reloading:
Collection after reloading with cell visible:
Collection after reloading with cell out of screen:
3D view of the cell after reloading:
The code:
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.sections.count;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)sectionIndex {
Section *section = [self.sections objectAtIndex:sectionIndex];
return section.items.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
Section *section = [self.sections objectAtIndex:indexPath.section];
Item *item = [section.items objectAtIndex:indexPath.row];
if (self.editing) {
EditingCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell-editing" forIndexPath:indexPath];
cell.item = item;
return cell;
} else {
BasicCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.item = item;
return cell;
}
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
HeaderCollectionReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"header" forIndexPath:indexPath];
Section *section = [self.sections objectAtIndex:indexPath.section];
header.title = section.title;
return header;
} else {
UICollectionReusableView *footer = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"footer" forIndexPath:indexPath];
return footer;
}
}
#implementation DetailCollectionViewLayout
- (instancetype)init {
if (self = [super init]) {
[self initialize];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initialize];
}
return self;
}
- (void)prepareLayout {
CGFloat cellWidth = (isIPAD) ? 288 : CGRectGetWidth(self.collectionView.bounds);
CGFloat headerWidth = CGRectGetWidth(self.collectionView.bounds);
// CGFloat ratio = (isIPAD) ? 0.33 : 0.66;
self.estimatedItemSize = CGSizeMake(cellWidth, 53);
self.headerReferenceSize = CGSizeMake(headerWidth, 50);
self.footerReferenceSize = CGSizeMake(headerWidth, 1 + self.minimumInteritemSpacing);
[super prepareLayout];
}
- (void)initialize {
self.minimumLineSpacing = 0;
self.minimumInteritemSpacing = (isIPAD) ? 5 : 10;
self.estimatedItemSize = CGSizeZero;
self.scrollDirection = UICollectionViewScrollDirectionVertical;
self.sectionInset = UIEdgeInsetsZero;
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
#end
I made a simple sample project and record a video: http://sendvid.com/330uo5jm
It looks like the issue is the position from the first cell.
UICollectionViewCell autosizing can be a little, uh... interesting even at the best of times. I've had this exact issue in the past, and similar issues too.
Use a different value for .estimatedItemSize, the closer to the actual item size the better. I noticed you're using a size of CGRectZero at first. I wouldn't recommend doing that. Just set it once, at the start, with a value close to your size. Try a few values, see what works for you. For me, it took a bit of fine tuning.
For anyone developing for iOS 10 (at the time of writing this hasn't been released) there is a new collection view property that lets the collection view determine the estimated size itself. Set the itemSize to UICollectionViewFlowLayoutAutomaticSize, you shouldn't need to set .estimatedItemSize explicitly.
make sure your estimatedItemSize in your code same as size of cell in your xib or storyboard.Don't changes it's size runtime.
can you check with use of identifier like...
NSString *CellIdentifier = [NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
Sometimes it happens if you have a big difference between estimated size and real size of cell.
Check you have a clear consequence of top to bottom constraints (if you are using autolayout).
Is there something that can break the autolayout to work properly ? E.g compresion resistance settings ?
Are you sure there are data for the cell after reload ? (Will be weird, but to be sure, just double check that.)
Also as Apple denotes here Apple - self sizing guide try to set the estimation of size as close as possible to real dimensions.
You can also try to refer to invalidation of collection layout as you are using your own. Refer to Possible flow-layout help
Try to set the estimation as close as possible and you will see if it solve your problem.
Related
Hi i am new for ios and in my app i have created one UITableView and i have set background image for UITableViewcell but image not filling the whole width of screen as like below screen. Why this problem is occuring?
I mean UITableViewCell left and right sides gap is coming images is not filling whole cell width.
please help me someone
my code:-
#import "TableViewController.h"
#interface TableViewController ()
{
UITableView * tableList;
TableCell * Cell;
}
#end
#implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
tableList = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, [[UIScreen mainScreen]bounds].size.height) style:UITableViewStylePlain];
tableList.delegate = self;
tableList.dataSource = self;
tableList.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:tableList];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"MyCell";
Cell = (TableCell *)[tableList dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (Cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableCell" owner:self options:nil];
Cell = [nib objectAtIndex:0];
}
//UIImageView *imageBackground = [[UIImageView alloc] init];
if (indexPath.row == 0) {
Cell.backGroundImage.image = [UIImage imageNamed:#"cell_top.png"];
} else if (indexPath.row == 9) {
Cell.backGroundImage.image = [UIImage imageNamed:#"cell_bottom.png"];
} else {
Cell.backGroundImage.image = [UIImage imageNamed:#"cell_middle.png"];
}
//imageBackground.contentMode = UIViewContentModeScaleToFill;
//Cell.backgroundView = imageBackground;
return Cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44.0;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if ([cell respondsToSelector:#selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:#selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
if ([cell respondsToSelector:#selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
#end
Try to set the layoutMargins property of the cells and the UITableView to UIEdgeInsetsZero.
- (void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
tableList.layoutMargins = UIEdgeInsetsZero;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[...]
Cell.layoutMargins = UIEdgeInsetsZero;
return Cell;
}
Also check for the contentMode of the UIImageview.
Cell.backGroundImage.contentMode = UIViewContentModeScaleAspectFill;
try set contentInset on Left = 0
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
Use Debug View Hierarchy to figure out UITableView, UITableViewCell or UIImage is not filling the whole width of screen
http://www.raywenderlich.com/98356/view-debugging-in-xcode-6
Please check your "TableCell" in the storyboard. Did you select custom insets option for your custom cell?
Rather than setting up your table view with code, you want to do this in a storyboard. Then you'll want to use auto layout to connect constraints from the table view to the view controller's view. There are lots of tutorials available to teach you how to do this. Learning this will make things much easier in the long run.
Change the name of your tableList property to tableView. That will make more sense to other developers (including yourself in the future), since that's what it is (a UITableView instance).
Your cell is named Cell with a capital C, but you don't want to name properties with capital letters. Also, it doesn't need to be a class property the way it's being used. Remove it from the #interface section.
Coding Guidelines for Cocoa
Remove the -numberOfSectionsInTableView: method. The default is 1, so you don't need code to return the default value.
Instead of -dequeueReusableCellWithIdentifier:, use -dequeueReusableCellWithIdentifier:forIndexPath:. Then you won't need to follow it with a test to see if a cell was returned (it always will be). You'll need to register your nib with -registerNib:forCellReuseIdentifier:. Or better yet, just design it in the storyboard.
It appears that your custom table view cell has a UIImageView named backGroundImage. That should be added as a subview to the cell's backgroundView property (which you'll need to create - the view, not the property, which is already part of UITableViewCell). Set the image view's autoresizingMask so it will resize with the backgroundView:
- (void)awakeFromNib
{
[super awakeFromNib];
self.backgroundView = [[UIView alloc] initWithFrame:self.bounds];
self.backGroundImage.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.backGroundImage.frame = self.backgroundView.bounds;
[self.backgroundView addSubview:self.backGroundImage];
}
Remove the -tableView:heightForRowAtIndexPath: method. You only want to use this if you return different values. The default row height is 44.0, so you don't need to do anything else.
Since I have been struggling for 3 days with this problem and have asked about it twice already, but maybe was not clear, I had decided to investigate the issue & found a buggy behavior with this view.
I will show the entire simple code, so anyone can reproduce the bug (iPad Air).
I am setting a collectionView flowlayout that subclasses the layout to get a constant spacing between cells, and here is the start:
TopAlignedCollectionViewFlowLayout *layout = [[TopAlignedCollectionViewFlowLayout alloc] init];
CGRect size = CGRectMake(0, 0, 900, 1200);
self.GridView = [[UICollectionView alloc] initWithFrame:size
collectionViewLayout:layout];
[self.GridView registerClass:[GridCell class] forCellWithReuseIdentifier:#"Cell"];
[self.GridView setDelegate:self];
[self.GridView setDataSource:self];
[self.view addSubview:self.GridView];
Then setting my delegates is as simple as that : (height is dynamic )
#pragma grid- main functions
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 80;
}
//cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
{
//a random dynamic height of a cell
int a = arc4random()%300;
CGSize size = CGSizeMake( 340, 240+a );
return size;
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
GridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:#"%d",indexPath.row];
NSLog(#"%d",indexPath.row);
return cell;
}
Now the subclass, to get a constant spacing : (TopAlignedCollectionViewFlowLayout)
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
#define numColumns 2
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns) {
CGRect f = currentItemAttributes.frame;
f.origin.y = 0;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns
inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat YPointNew = fPrev.origin.y + fPrev.size.height + 10;
CGRect f = currentItemAttributes.frame;
f.origin.y = YPointNew;
currentItemAttributes.frame = f;
return currentItemAttributes;
}
Anyone can check and see that after you scroll for a while, you get a strange effect of blank spaces that are filled lately by their cells,something like :
1 2
3 4
6
8
NOTE: 5-7 are loaded in later.
EDIT1:
Removing the random height from the cell size delegate method, set it to be constant height, solves this issue.
Problem is: Cell's height must be dynamic.
EDIT2:
Setting the random height (int a) to be smaller, makes also the problem to disappear,(<100), means that the smaller the distance height between cells, more likely the problem will not occur .
EDIT3 !
I have managed to set a constant distance between cells, not with subclass of the layout, but with my own memory by saving the previous cell origin and height, so i have got the constant spacing but the problem is back again ! seems that if the cells are in some certain structure, it makes the callback method that create cells, to not being called in time ! wow , i am really wondering how no one had seen this before ..
here is my implementation to create spacing with no subclassing,that also cause the problem:
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
GridCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.textL.text=[NSString stringWithFormat:#"%ld",(long)indexPath.row];
NSLog(#"%d",indexPath.row);
if(indexPath.row>1)
{
NSIndexPath* ipPrev = [NSIndexPath indexPathForItem:indexPath.item-2 inSection:indexPath.section];
float prey=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"y:%ld",(long)ipPrev.row]] floatValue];
float preh=[[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"h:%ld",(long)ipPrev.row]] floatValue];
cell.frame=CGRectMake(cell.frame.origin.x, preh+prey+10, cell.frame.size.width, cell.frame.size.height);
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.origin.y forKey:[NSString stringWithFormat:#"y:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] setFloat:cell.frame.size.height forKey:[NSString stringWithFormat:#"h:%ld",(long)indexPath.row]];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"this index:%d",indexPath.row);
NSLog(#"this cell y:%f",cell.frame.origin.y);
NSLog(#"this cell height:%f",cell.frame.size.height);
NSLog(#"previous index:%ld",(long)ipPrev.row);
NSLog(#"previous cell y: %#",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"y:%ld",(long)ipPrev.row]]);
NSLog(#"previous cell height: %#",[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"h:%ld",(long)ipPrev.row]]);
NSLog(#"------------------------");
}
return cell;
}
Seems its a serious bug in UICollectionView, when images are bigger than screen size.
1 . UICollectionView fall back to UIScrollView
2.Large UICollectionViewCell's disappearing with custom layout
3.http://stripysock.com.au/blog/2013/3/14/working-around-a-bug-in-uicollectionview
So much work and time, for this stupid bug of apple with the reusable cells that causes nothing but headache with so many strange behaviours.
For developers who didn't have the problem i can say- just try to set dynamic height images, and iPad simulator, and you will see bugs that are just unbelievable.
So no answer for me, i will have to implement the whole thing by my self with a scrollview ,since i dont want to be depended again on things such PSTCollectionView
Working in iOS 7, how does one specify where the header & footer boxes go in a UICollectionView?
I have a custom UICollectionViewFlowLayout. I have overwritten
-(void)prepareLayout
-(NSArray*) layoutAttributesForElementsInRect:(CGRect)rect
-(UICollectionViewLayoutAttributes*) layoutAttributesForSupplementaryViewOfKind: (NSString*)kind atIndexPath:(NSIndexPath*)indexPath
My problem is, I'm not sure how to specify header location. I have already specified that a header exists in prepareLayout:
-(void)prepareLayout
{
[super prepareLayout];
boundsSize = self.collectionView.bounds.size;
midX = boundsSize.width / 2.0f;
curIndex = 0;
self.headerReferenceSize = CGSizeMake(CELL_SIZE, TITLE_HEIGHT);
self.footerReferenceSize = CGSizeMake(0, 0);
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.sectionInset = UIEdgeInsetsMake(TOP_INSET, LEFT_INSET, BOTTOM_INSET, RIGHT_INSET);
self.minimumLineSpacing = LINE_SPACING;
self.minimumInteritemSpacing = INTERIM_SPACING;
self.itemSize = CGSizeMake(CELL_SIZE, CELL_SIZE);
}
I just don't know the right property of my custom FlowLayout to set, as there doesn't seem to be something like "HeaderLocation" to set, either as a LayoutAttributes or in the layout object itself. Right now, it is appearing to the side/between my images, when I'd like them to be appearing above each image (horizontal scroll).
I have tried the following:
-(UICollectionReusableView*) collectionView: (UICollectionView*)collectionView viewForSupplementaryElementOfKind:(NSString*)kind atIndexPath:(NSIndexPath*)indexPath
{
NSLog(#"**ViewForSupplementaryElementOfKind called***");
CGFloat centerX = collectionView.center.x;
CGFloat centerY = collectionView.center.y;
CGFloat titleWidth = [MyLayout titleWidth];
CGFloat titleHeight = [MyLayout titleHeight];
MyTitleView* titleView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:ImageTitleIdentifier forIndexPath:indexPath];
titleView.frame = CGRectMake(centerX - titleWidth/2.0,
0.0,
titleWidth,
titleHeight);
return titleView;
}
This doesn't work. The title appears above overlapped with a bunch of other titles, then the moment I start scrolling (horizontally), they jump back into the wrong place, horizontally between the images rather than above.
PS> Please do not suggest anything that has to do with NIB or XIB placement. I am using a UICollectionView, NOT a UICollectionViewController, so I actually have no prototypical cell to work with. The layout is being done entirely programatically -- from code alone -- so I can't simply open a XIB file and adjust the location of a text box.
Amending the attributes returned by -layoutAttributesForElementsInRect is the right approach, but if you want to alter the position of offscreen headers and footers, you may need to fetch the supplementary view attributes yourself.
For example, in your UICollectionViewFlowLayout subclass:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *attributesArray = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
// the call to super only returns attributes for headers that are in the bounds,
// so locate attributes for out of bounds headers and include them in the array
NSMutableIndexSet *omittedSections = [NSMutableIndexSet indexSet];
for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
if (attributes.representedElementCategory == UICollectionElementCategoryCell) {
[omittedSections addIndex:attributes.indexPath.section];
}
}
for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
[omittedSections removeIndex:attributes.indexPath.section];
}
}
[omittedSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
atIndexPath:indexPath];
[attributesArray addObject:attributes];
}];
for (UICollectionViewLayoutAttributes *attributes in attributesArray) {
if ([attributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
// adjust any aspect of each header's attributes here, including frame or zIndex
}
}
return attributesArray;
}
CollectionView Header height is set below Collectionview delegate
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
And Set view in Collectionview Header in Below Delegate
- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView * view = nil;
if ([kind isEqualToString:UICollectionElementKindSectionHeader])
{
ColorSectionHeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
withReuseIdentifier:NSStringFromClass([ColorSectionHeaderView class])
forIndexPath:indexPath];
header.sectionIndex = indexPath.section;
header.hideDelete = collectionView.numberOfSections == 1; // hide when only one section
header.delegate = self;
view = header;
}
return view;
}
Ragistred Class in ViewDidLoad
-(void)ViewDidLoad
{
[collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([ColorSectionFooterView class]) bundle:nil]
forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
withReuseIdentifier:NSStringFromClass([ColorSectionFooterView class])];
[Super ViewDidLoad];
}
I have a UICollectionViewCell subclass called AlbumCVC that contains a single IBOutlet --- a UIImageView called cellView. I'm setting the value of cellView for each cell inside the following method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell;
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"albumPhotoCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blueColor];
if ([cell isKindOfClass:[AlbumCVC class]]){
AlbumCVC *albumCVC = (AlbumCVC *)cell;
ALAsset *thisImage = [self.albumPhotos objectAtIndex:indexPath.item];
albumCVC.imageView.frame = albumCVC.contentView.frame;
albumCVC.contentView.contentMode = UIViewContentModeScaleAspectFit;
albumCVC.imageView.image = [UIImage imageWithCGImage:[thisImage aspectRatioThumbnail]];
}
}
return cell;
}
where albumPhotos is an NSMutableArray of ALAssets. I'm sure that the property is getting set correctly because I get sensible results when I log the albumCVC.cellImage.image.bounds.size. Cells are also sized properly as the frames are visible when I set the background color. But for some reason, cellImage won't display. Is there another method call I need to make inside collectionView:cellForItemAtIndexPath: in order to get the image to show up?
Update: On the advice of a very smart friend, I tried moving the UIImageView out of the cell, putting it elsewhere in the main view, and everything worked lovely. The problem appears to have something to do with the frame / bounds of the UIImageView. I think there's a method call I need to make so that the cell's subview expands to fit the newly-resized cell following the call to collectionView:layout:sizeForItemAtIndexPath:. The problem now is that UIImageView.image.size is a read-only property, so I can't resize it directly.
Update 2: On another piece of advice I looked at the frame and bounds of the cell's contentView and cellImage and found that they weren't matching up. Added another method call to make them equal, and even changed contentMode to UIViewContentModeScaleAspectFit in order to try and get the cell to render the thumbnail properly. Unfortunately, I'm still getting tiny thumbnails inside huge cells. Any idea why? Updated code above and below.
For the sake of completeness, here's the entire class implementation:
#import "AlbumViewController.h"
#import "AlbumCVC.h"
#import <AssetsLibrary/AssetsLibrary.h>
#interface AlbumViewController ()
#end
#implementation AlbumViewController
#pragma constants
const int IPHONE_WIDTH = 320;
#pragma delegate methods
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section{
// Get the count of photos in album at index albumIndex in the PhotoHandler
NSInteger numCells = [self.group numberOfAssets];
return numCells;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell;
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"albumPhotoCell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor blueColor];
if ([cell isKindOfClass:[AlbumCVC class]]){
AlbumCVC *albumCVC = (AlbumCVC *)cell;
ALAsset *thisImage = [self.albumPhotos objectAtIndex:indexPath.item];
}
albumCVC.imageView.frame = albumCVC.contentView.frame;
albumCVC.contentView.contentMode = UIViewContentModeScaleAspectFit;
albumCVC.imageView.image = [UIImage imageWithCGImage:[thisImage aspectRatioThumbnail]];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
//Copy a pointer to an asset from the album
ALAsset *thisImage = [self.albumPhotos objectAtIndex:indexPath.item]; //Zen - are you sure thisImage represents a valid image?
//Copy that asset's size and create a new size struct
CGSize thisSize = thisImage.defaultRepresentation.dimensions;
CGSize returnSize;
// force all previews to be full width
returnSize.width = IPHONE_WIDTH;
returnSize.height = IPHONE_WIDTH * thisSize.height / thisSize.width;
return returnSize;
}
#pragma lifecycle methods
- (void)viewWillAppear:(BOOL)animated{
[self.albumPhotos removeAllObjects];
//"handler" is a class that manages calls to the ALAssetLibrary. self.albumIndex is an integer that gets set on segue. As far as I can tell, everything in the below method is working fine --- cells are sized properly.
self.group = self.albumDelegate.handler.groups[self.albumIndex];
[self.group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result) {
NSLog(#"Just added an object to albumPhotos.");
[self.albumPhotos addObject:result];
NSLog(#"The item in albumPhotos is class %#", [self.albumPhotos[0] class]);
}
}];
}
#pragma instantiation
- (ALAssetsGroup *)group{
if (!_group) {
_group = [[ALAssetsGroup alloc]init];
}
return _group;
}
- (NSMutableArray *)albumPhotos{
if (!_albumPhotos) {
_albumPhotos = [[NSMutableArray alloc]init];
}
return _albumPhotos;
}
#end
Update 3: I can't be certain what the problem was initially, but I know that it now works with the following cellForItem implementation:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell;
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"albumPhotoCell" forIndexPath:indexPath];
if ([cell isKindOfClass:[AlbumCVC class]]) {
AlbumCVC *albumCVC = (AlbumCVC *)cell;
albumCVC.albumImageView.image = [[UIImage alloc] initWithCGImage:[self.albumAssets[[self reverseAlbumIndexForIndex:indexPath.item]] thumbnail]];
}
cell.alpha = [self alphaForSelected:self.selectedItems[#(indexPath.item)]];
return cell;
}
There's no screwing around with frames or bounds anywhere, everything just works. Maybe it's the difference between [[UIImage alloc]initWithCGImage] and [UIImage imageWithCGImage]?
I've had a similar issue and resolved it by setting the UICollectionViewCell frame property to be the same as the UIImageView's frame. I'm not 100% sure that this is your issue, I was building the collection purely in code (no Storyboard)
I have a CollectionViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// assign layout (subclassed below)
self.collectionView.collectionViewLayout = [[CustomCollectionLayout alloc] init];
}
// data source is working, here's what matters:
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ThumbCell *cell = (ThumbCell *)[cv dequeueReusableCellWithReuseIdentifier:#"ThumbCell" forIndexPath:indexPath];
return cell;
}
I also have a UICollectionViewLayout subclass: CustomCollectionLayout.m
#pragma mark - Overriden methods
- (CGSize)collectionViewContentSize
{
return CGSizeMake(320, 480);
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
return [[super layoutAttributesForElementsInRect:rect] mutableCopy];
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
// configure CellAttributes
cellAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
// random position
int xRand = arc4random() % 320;
int yRand = arc4random() % 460;
cellAttributes.frame = CGRectMake(xRand, yRand, 150, 170);
return cellAttributes;
}
I'm trying to use a new frame for the cell, just one at a random position.
The problem is layoutAttributesForItemAtIndexPath is not called.
Thanks in advance for any advice.
Edit: I didn't notice that you've solved your case, but I had the same problem and here's what helped in my case. I'm leaving it here, it may be useful for someone given that there's not much on this topic yet.
Upon drawing, UICollectionView does not call the method layoutAttributesForItemAtIndexPath: but layoutAttributesForElementsInRect: to determine which cells should be visible. It's your responsibility to implement this method and from there call layoutAttributesForItemAtIndexPath: for all visible index paths to determine exact locations.
In other words, add this to your layout:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray * array = [NSMutableArray arrayWithCapacity:16];
// Determine visible index paths
for(???) {
[array addObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:??? inSection:???]]];
}
return [array copy];
}
Was an issue with Storyboard parameters. Assigned custom UICollectionLayout from Inspector panel.