I created a collection view cell with the Xib file. And I have only one cell, but that cell displaying in the center of the collectionView. I want to display cell at starting position of the collectionView.
I fixed contentInset in viewDidLoad and loading cell xib file here,
_listCollectionView.contentInset = UIEdgeInsetsMake(0 , 0, 0, 0);
And my cell size is
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(156,140);
}
Cell displaying like this.
Im not very clear with your question but i think what you are referring to is to align the collectionnView element to the view . You have to use UICollectionViewLayoutAttributes or layoutAttributesforElements to achieve this . Take look at the below code and to make if you want it in Objective c.
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.
CGFloat maxY = -1.0f;
//this loop assumes attributes are in IndexPath order
for (UICollectionViewLayoutAttributes *attribute in attributes) {
if (attribute.frame.origin.y >= maxY) {
leftMargin = self.sectionInset.left;
}
attribute.frame = CGRectMake(leftMargin, attribute.frame.origin.y,
attribute.frame.size.width, attribute.frame.size.height);
leftMargin += attribute.frame.size.width + self.minimumInteritemSpacing;
maxY = MAX(CGRectGetMaxY(attribute.frame), maxY);
}
return attributes;
}
In collectionView: cellForItemAtIndexPath: function i made changes like this.
Here just i fixed my collectionviewcell x origin position to 0 after loading the cell.
deviceCell= (DeviceCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"DeviceCollectionViewCell" forIndexPath:indexPath];
if (listArray.count == 1) {//Here i fixed the my cell x origin position
CGRect frameRect = deviceCell.frame;//Copy cell frame
frameRect.origin.x = 0;//Set cell origin.x
deviceCell.frame = frameRect;//Reset frame
}
Related
I have UICollectionView with customLayOut, when I start scrolling,
I change x coordinate for the cell that should start to be visible - in order to be visible from the begining.
-(void)layoutSubviewsWithAttributes:(NSMutableArray *)theAttributes {
CGFloat halfScreen = [UIScreen mainScreen].bounds.size.width / 2;
CGPoint startOfScreen = CGPointMake(self.timeLineCollection.bounds.origin.x, 25.f);
for(UICollectionViewLayoutAttributes *attribute in theAttributes) {
if(CGRectContainsPoint(attribute.frame, startOfScreen)) {
NSLog(#"Intersect %#", NSStringFromCGRect(attribute.frame));
attribute.frame = CGRectMake(startOfScreen.x, startOfScreen.y, attribute.frame.size.width, attribute.frame.size.height);
}
}
but in some cases this cell appears on the top of the next one cell (wrong behaviour),
another time, that cell in under the next one cell (as I need it to be placed).
Could you advice, how to sort that cells to be placed hierarchically one on another (like cards).
Thank you in advance, for any help.
Try this with negative value it may help as i haven't tried but i am sure it should work like this.
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return -5.0;
}
UICollectionViewLayoutAttributes has such a property as zIndex, that - Specifies the item’s position on the z axis.
So to tell cells to be set one after another, I just set to each attribute, zIndex - number of each cell and it places it one after another, inside the customLayOut.
for (NSInteger item = 0; item < self.cellCountPrograms; item++) {
indexPath = [NSIndexPath indexPathForItem:item inSection:0];
UICollectionViewLayoutAttributes *itemAttributes =
[UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
itemAttributes.frame = [self frameForItemAtIndexPath:indexPath];
itemAttributes.zIndex = item;
cellProgramLayoutInfo[indexPath] = itemAttributes;
}
I'm using UICollectionViewFlowLayout and wanted to apply section insets like below. All my items have the same width but varying heights. The insets work when items within the same section are the same height but not when they are different heights in the same section. Is this expected behaviour for this layout? Do I need to subclass and make a custom one or is something missing?
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
UIEdgeInsets insets = UIEdgeInsetsZero;
CGFloat big = 30;
CGFloat small = 10;
if (section < 5) {
insets = UIEdgeInsetsMake(0, big, 0, small);
} else {
insets = UIEdgeInsetsMake(0, small, 0, big);
}
return insets;
}
For some reason the UICollectionViewFlowLayout has the behaviour to center the cells if you have a single item each row. It ignores the section insets then.
You can solve this issue by overriding the UICollectionViewFlowLayout and change the following two methods:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attribute = [super layoutAttributesForItemAtIndexPath:indexPath];
[self fixLayoutAttributeInsets:attribute];
return attribute;
}
And
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *results = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes *attribute in results)
{
[self fixLayoutAttributeInsets:attribute];
}
return results;
}
The magic:
- (void)fixLayoutAttributeInsets:(UICollectionViewLayoutAttributes *)attribute
{
if ([attribute representedElementKind])
{ //nil means it is a cell, we do not want to change the headers/footers, etc
return;
}
//Get the correct section insets
UIEdgeInsets sectionInsets;
if ([[[self collectionView] delegate] respondsToSelector:#selector(collectionView:layout:insetForSectionAtIndex:)])
{
sectionInsets = [(id<UICollectionViewDelegateFlowLayout>)[[self collectionView] delegate] collectionView:[self collectionView] layout:self insetForSectionAtIndex:[[attribute indexPath] section]];
}
else
{
sectionInsets = [self sectionInset];
}
//Adjust the x position of the view, the size should be correct or else do more stuff here
CGRect frame = [attribute frame];
frame.origin.x = sectionInsets.left;
[attribute setFrame:frame];
}
This solution does not work (and is not needed) if you have multiple cells on a single row so you should check for that case with a boolean or whatever you like... This is just a simple example for this scenario
Doesn't seem to be possible with varying heights, so I made the cells full width and mange the padding logic inside the cell class itself.
I was trying to subclass collection view layout , in order to get a constant spacing between vertical cells. i have 2 columns and many rows, with dynamic cells height .
The goal is Pinterest like grid.
So i have subclassed the layout class, and now has a constant space between cells, but there is a serious problem caused by that .
When i scroll down, the left cells are not being loaded in time= there are many "holes" so that there is blank space of 3-4 cells, and than- they suddenly appears at once -lately.
so i have this :
1 2
3 4
6
8
than 5 and 7 appears when i scroll down more . i just can't get rid of this !
EDIT: seems that when all cells are in the same size, this will not happens ,so when i return here a constant height :
//cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
{
CGSize size=CGSizeMake( imageWidth, scale*height+[Globals sharedGlobals].gridViewStripHeight );
return size;
My subclass(which when not using it, also solves the problem )
//the subclass
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray* arr = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* atts in arr)
{
if (nil == atts.representedElementKind)
{
NSIndexPath* ip = atts.indexPath;
atts.frame = [self layoutAttributesForItemAtIndexPath:ip].frame;
}
}
return arr;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes* atts =[super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item == 0 || indexPath.item == 1) // degenerate case 1, first item of section
return atts;
NSIndexPath* ipPrev =
[NSIndexPath indexPathForItem:indexPath.item-2 inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat rightPrev = fPrev.origin.y + fPrev.size.height + 50;
if (atts.frame.origin.y <= rightPrev) // degenerate case 2, first item of line
return atts;
CGRect f = atts.frame;
f.origin.y = rightPrev;
atts.frame = f;
return atts;
}
To use it i have :
UICollectionViewFlowLayout *layout=[[TopAlignedCollectionViewFlowLayout alloc] init]; subclass
CGRect size=CGRectMake( ([UIScreen mainScreen].bounds.size.width-collectionWidth)/2,
upperLineMargin, collectionWidth, [UIScreen mainScreen].bounds.size.height-upperLineMargin);
self.GridView=[[UICollectionView alloc] initWithFrame:size collectionViewLayout:layout];
[self.GridView registerClass:[GridCell class] forCellWithReuseIdentifier:#"Cell"];
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 UICollectionView which uses a waterfall style layout to show different sized cells. The height calculation for each cell works just fine.
The problem I have is that I have to change the size of two outlets (UIImage and UILabel) in each cell and I don´t know where to change the frame size in order prevent the UICollectionView from animating said frame size change. I tried it to do in the layoutSubviews method of each cell and in the cellForItemAtIndexPath without results. Every time the viewcontroller containing the UICollectionView appears the frame change for the two outlets in each cell is animated.
Example setting the frame for just the image inside cellForItemAtIndexPath:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CVCNewspaper *cell = (CVCNewspaper *)[collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER_NEWSPAPER forIndexPath:indexPath];
BONewspaper *newspaper = [newspapers objectAtIndex:indexPath.row];
CGFloat width = cell.frame.size.width;
// Calculate rect for imageView
CGFloat objectWidth = newspaper.coverNews.imageWidth ? newspaper.coverNews.imageWidth : 180;
CGFloat objectHeight = newspaper.coverNews.imageHeight ? newspaper.coverNews.imageHeight : 100;
CGFloat scaledHeight = floorf(objectHeight / (objectWidth / width));
cell.imageViewCover.frame = CGRectMake(MARGINVIEW, HEADERHEIGHT + 5, width, scaledHeight);
[cell fillCellWithNewspaper:newspaper];
return cell;
}