So I have been have some issues with UICollectionView which seems to be a common theme on the internet. Here, Here and Here. I have tried the links suggestions. So just some context.
1.) I'm pulling data from Parse.com (no issue there)
2.) The results are looped over and populated in an array to then fill out the cell. (just like a UITableView)
3.) The data is text based only and populates accordingly, no images to deal with at the moment ;-).
The issue seems to be when I render the dataset. I have set the line spacing between each row to be the following;
//reduce each section to 1px so that it looks like a record set.
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
//reduce each section to 1px so that it looks like a record set.
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *) collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
//UIEdgeInsetsMake(top, left, bottom, right);
return UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
}
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
return YES;
}
This works accordingly. AFTER you scroll (see below screenshots)
Wrong Render
Correct Render
Cell Code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"cell";
PatternCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
PFObject *cellObject = [flightRecordData objectAtIndex:indexPath.row];
/* ALL THE UILABEL ELEMENTS ARE SET HERE JUST REMOVED TO SAVE SPACE */
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
[cell.layer setNeedsDisplay];
return cell;
}
I'm happy to deal with the rendering issue because apart from that it works. However, my OCD is kicking in and its doing my head in trying to work out what the issue is. I have even deployed to the device to see if its a simulator issue which its not. Each of the suggested posts from others I have tried but didn't seem to work.
Any ideas on how to fix this? I'm new to iOS so be gentle :-P.
UPDATE:
Thanks for the feedback, below is the class and screen shots of the storyboard. I'm using the custom class just as an object that I call when required.
Custom UICollectionViewCell Class
#interface PatternCollectionViewCell : UICollectionViewCell {
IBOutlet UILabel *pilotNameLabel;
IBOutlet UILabel *pilotTotalHoursLabel;
//etc etc...
}
#property (nonatomic,strong) IBOutlet UILabel *pilotNameLabel;
#property (nonatomic,strong) IBOutlet UILabel *pilotTotalHoursLabel;
Storyboard
CollectionView
CollectionViewCell
CustomCell
You had a mismatch between the item size given in the flow layout (configured on the collection view in Interface Builder), which gave the height as 58 pixels high, and the size of the custom cell, which had a height of only 52 pixels.
This explains the extra spacing around the cell.
Related
In my project i have collection ,in which horizontal pagination is enabled, Every thing working fine but, when i scroll,particular cell item not fit entire cell,It show half image of previous cell item and half current Items, i need One item to fit the entire screen ??? Any suggestion are welcome
Here is the code:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; {
SingleItemCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"SingleItemCollectionViewCell" forIndexPath:indexPath];
[cell ConfigaureCollectionViewItem:self.totalCellItems[indexPath.row]]; return cell;
}
-(CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = CGSizeMake(self.bounds.size.width - 20, self.bounds.size.height - 40);
return size;
}
Perhaps you should be using UIPageViewController in stead of UICollectionView. From your question it seems that you are trying to mimic the behaviour of the former.
I'm building a status item kind of thing for a UICollectionView. My problem is when I want to add some text to the status area I can't get the thing to auto resize to the new text. I have auto layout on and I've tried all kinds of things found on stacky.
The one which I think is the closest to being correct is this:
-(UICollectionViewCell *) collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
StatusItemModel *statusModel = [self.items objectAtIndex[indexPath indexPosition:0]];
StatusItemEventCell *statusCell = [collectionView dequeueResusableCellwithReuseIdentifier: #"EventStatusItem" forIndexPath:indexPath];
statusCell.statusTitleLabel.text = [statusModel.statusDetails valueForKey:#"title"];
statusCell.statusContentTextView.text = [statuaModel.statusDetails valueForKey:#"content"];
[statusCell layoutIfNeeded];
return statusCell;
}
// After which I believe we have to do some magic in this but what?
- (CGSize) collectionView:(UiCollectionView *) collectionView layout:(UICollectionViewLayout *) collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
// How do I get the size of the textview statusContentTextView.text?
// With that I'll be able to figure out what needs to be returned.
return CGSizeMake(299.f, 200.f);
}
The autolayout is setup with constraints for all elements in the cell. I've even played around with the intrinsic size and placeholders, however still now luck. Please can someone point me in the right direction.
So after going around in circles thinking there was a better way, no we need to know the size before we can set the size of the cell for the collection view. Pretty counter productive, because sometimes we don't know the size of it at run time. The way I solved this was to create a mock UITextView object and then called sizeThatFits.
So here is what I did with my code:
- (CGSize) collectionView:(UICollectionView *) collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
StatusItemModel *statusModel = [self.items objectAtIndex:[indexPath indexAtPosition:0]];
UITextView *temporaryTextView = [[UITextView alloc] init];
temporaryTextView.text = [statusModel.statusDetails valueForKey:#"content"];
CGSize textBoxSize = [temporaryTextView sizeThatFits:CGSizeMake(299.0f, MAXFLOAT)];
// Can now use the height of the text box to work out the size of the cell and
// the other components that make up the cell
return textBoxSize;
}
I try to make UICollectionView with cells, that intersect and partially overlay each other as it is done at screenshot:
This layout was reached by setting
self.minimumLineSpacing = -100;
at my UICollectionViewFlowLayout subclass.
When I scroll down, everything is OK. I see what I want. But when I scroll up, I see another behaviour, not like I expected:
So my question is: how can I make my layout look as at the first screen regardless scroll view direction.
Note: I have to support both iOS 6 and 7.
Thanks very much for any advices and any help.
Hmm, interesting. Since the collection view recycles cells, they are continuously added to and removed from the view hierarchy as they move on and off the screen. That being said, it stands to reason and when they are re-added to the view, they are simply added as subviews meaning that when a cell gets recycled, it now has the highest z-index of all of the cells.
One fairly pain-free way to rectify this would be to manually adjust the z position of each cell to be incrementally higher with the index path. That way, lower (y) cells will always appear above (z) the cells above (y) them.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"CELLID";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
if (cell.layer.zPosition != indexPath.row) {
[cell.layer setZPosition:indexPath.row];
}
return cell;
}
Found another sollution to solve this problem. We need to use UICollectionViewFlowLayout subclass.
#interface MyFlowLayout : UICollectionViewFlowLayout
#end
#implementation MyFlowLayout
- (void)prepareLayout {
[super prepareLayout];
// This allows us to make intersection and overlapping
self.minimumLineSpacing = -100;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes *currentLayoutAttributes in layoutAttributes) {
// Change zIndex allows us to change not only visible position, but logic too
currentLayoutAttributes.zIndex = currentLayoutAttributes.indexPath.row;
}
return layoutAttributes;
}
#end
Hope that helps someone else.
I need to have just simple UICollectionViewCell style with cells on top of eachoher. Like tableview. But I need Dynamic height dependent of the content, size the content is comments it can vary.
I got
viewDidLoad:
[self.commentsCollectionView registerClass:[GWCommentsCollectionViewCell class] forCellWithReuseIdentifier:#"commentCell"];
in .h I got:
and I #import my custom UICollectionViewCell that sets all constraints with programmatic autolayout.
I instantiate the UICollectionView with:
UICollectionViewFlowLayout *collViewLayout = [[UICollectionViewFlowLayout alloc]init];
self.commentsCollectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:collViewLayout];
I use autolatyout to get the UICollectionView be where I want (thats why CGRectZero).
And finally I was hoping to do this:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
GWCommentsCollectionViewCell *cell = (GWCommentsCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
return cell.singleCommentContainerview.bounds.size;
}
singleCommentContainerview is a direct subview of the contentView and withing the singleCommentContainerview I have UILabels, UIImageViews etc, all set witih autolayoutcode.
But I just get cgsize value of (0,0)
How can I fix this to get the proper size I need for each cell?
From what I have read UICollectionView needs the sizes worked out before laying out the cell. So the above method of yours that cell hasn't yet been drawn so it has no size. Also it could be an issue or combined with the issue that the cell is cached/pooled with the same identifier #"commentCell", I tag unique cells with a new identifier and class normally.
My thoughts are to catch the cell before it is drawn, push the size into a dictionary for use later, using:
- (void)collectionView:(UICollectionView *)collectionView
willDisplayCell:(UICollectionViewCell *)cell
forItemAtIndexPath:(NSIndexPath *)indexPath{
GWCommentsCollectionViewCell *cell = (GWCommentsCollectionViewCell*)[collectionView cellForItemAtIndexPath:indexPath];
// Need to add it to the view maybe in order for it the autolayout to happen
[offScreenView addSubView:cell];
[cell setNeedsLayout];
CGSize *cellSize=cell.singleCommentContainerview.bounds.size
NSString *key=[NSString stringWithFormat:#"%li,%li",indexPath.section,indexPath.row];
// cellAtIndexPath is a NSMutableDictionary initialised and allocated elsewhere
[cellAtIndexPath setObject:[NSValue valueWithCGSize:cellSize] forKey:key];
}
Then when you need it use that dictionary based off the key to get the size.
Its not a really super pretty way as its dependent on the views being drawn, autolayout doing its thing before you get the size. And if you are loading images even more it could throw up issues.
Maybe a better way would be to preprogram the sizes. If you have data on the images sizes that may help. Check this article for a really good tutorial (yah programatically no IB):
https://bradbambara.wordpress.com/2014/05/24/getting-started-with-custom-uicollectionview-layouts/
Add
class func size(data: WhateverYourData) -> CGSize { /* calculate size here and retrun it */}
to your custom cell and instead of doing
return cell.singleCommentContainerview.bounds.size
it should be
return GWCommentsCollectionViewCell.size(data)
I am implementing a Table for iPad and facing some major problems.
For the GridView I implemented my own subclass of UITableViewCell which works fine.
The data is shown correctly, but I have a problem when I want to access a single cell to go to some new detail view. Since one row only contains one cell, the didSelectRowAtIndexPath only gives me access to the complete cell, but I don't know which column the single cell is in.
Then I implemented a TapGestureRecognizer. This shows me the row and column and works, but only until I start scrolling... the column part still works, but the row is shown incorrect since the TapRecognizer overlaps the didSelectRowAtIndexPath (bad but not so important side effect.. there is no blue highlighting of the selected row).
Is there a way to find out how many pixels I scrolled? Or is there an even better solution?
I highly recommend using UICollectionView over those 3rd party classes. There are quite a few advantages to having access to all of the delegate protocols (like showing the cut copy paste UIMenuController on a long press without a UIGestureRecognizer, for example) I use one myself as a grid.
To acheive a grid layout, I did the following...
1) I set the following Delegates in my .h file:
#interface YourViewControllerWithCollectionView : UIViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout> {
}
#property (nonatomic, retain) IBOutlet UICollectionView *myCollectionView;
#end
Notice, that I did not set the UICollectionViewDelegate because UICollectionViewDelegateFlowLayout is actually a sub-protocol of UICollectionViewDelegate, so there is no need to set both.
2) In the .m file, synthesize the collection view, and in viewDidLoad declare the datasource and delegates: (don't forget to connect your outlets, and you might want to put a background color on the cell so you can see it)
#synthesize myCollectionView;
viewdidLoad:
- (void)viewDidLoad
{
self.myCollectionView.delegate = self;
self.myCollectionView.dataSource = self;
//...
}
3) Implement the datasource
#pragma mark - UICollectionView Datasource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
//the number of cells you want per row
return 4;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
//load sublassed UICollectionViewCell called MyCollectionViewCell
static NSString *cellIdentifier = #"cell";
MyCustomCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
cell.title.text = #"Title"
// customize the cell...
return cell;
}
5) Implement the UICollectionViewDelegateFlowLayout
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//this is what forces the collectionview to only display 4 cells for both orientations. Changing the "-80" will adjust the horizontal space between the cells.
CGSize retval = CGSizeMake((myCollectionView.frame.size.width - 80) / 4, 78);
return retval;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// for the entire section, which we have set to 1, adjust the space at
// (top, left, bottom, right)
// keep in mind if you change this, you will need to adjust the retVal
// in the method above
return UIEdgeInsetsMake(5, 20, 10, 20);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
CGFloat interimSpacing = 0.0f;
return interimSpacing;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
CGFloat lineSpacing = 0.0f;
return lineSpacing;
}
6) Last, but certainly not least, invalidate the layout on orientation change to redraw the cells:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration{
[self.myCollectionView.collectionViewLayout invalidateLayout];
}
And because you implemented UICollectionViewDelegateFlowLayout, you already have access to UICollectionViewDelegate to handle selection, etc. like:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
//do something when a cell is tapped...
}
More information can be found here: http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12
Look at AQGridView or some of the other controls at CocoaControls.com.
I recommend AGAINST UICollectionView. UICollectionView is easy to use, but not stable enough at this moment. I am using GMGridView for my apps. After a few months operations, I can say that it is stable enough for the production release. Another alternative is PSTCollectionView, which is a 100% API compatible replacement for UICollectionView. However, it is unfinished and contains even more bugs than UICollectionView.
The disturbing issues I have with PSTCollectionView are:
poor performance if you want to display > 80 cells on screen
reloading sections is not implemented
decoration views are not implemented
The disturbing issues I have with UICollectionView are:
the items in the first column may disappear
inserting the first cell will crash
reloading sections with header view will crash
blurry text in cells
Check open radar
https://openradar.appspot.com/search?query=UICollectionView
for all current issues with UICollectionView.
I believe UICollectionView and PSTCollectionView will be good choices when they are stable. But at this moment, GMGridView is a better choice.