Display section header on top with UICollectionViewFlowLayout scrolling set to horizontal - ios

This is a duplicate of this question. I'm asking again because the accepted answer is not working and no one's providing more explanation on how the supposed correct answer works.
So here's the situation: I want to display the collection view into one single row. To do this, I applied a custom UICollectionViewFlowLayout to the collection view and set the scrolling to horizontal. Everything is working fine, except for section header disappeared.
To remedy this, I implemented this function:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeMake(350, 35);
}
Now the header is shown, but the problem is it is displayed to the left of the cells, instead of the usual top.
I stumbled upon the link above while searching for a solution, but like I've said, the accepted answer is not working at all and I could not find other solutions about this situation. So can anyone help me here?

we can do that by using the delegate method -
(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
and keeping the left inset to minus value of width of supplementary view and managing the top inset

Have you tried using the header with something like this?
First: set it up in viewDidLoad...
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.headerReferenceSize = CGSizeMake(self.collectionView.bounds.size.width, 30);
// add any other setup you need
[self.collectionView setCollectionViewLayout:flowLayout];
Second: add header view ...
#define LABEL_TAG 128
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
UICollectionElementKindSectionHeader withReuseIdentifier:#"SectionHeader" forIndexPath:indexPath];
UILabel *label = (UILabel *)[headerView viewWithTag:LABEL_TAG];
if (!label) {
label = [[UILabel alloc] initWithFrame:CGRectInset(headerView.bounds, 5, 5)];
label.tag = MY_HEADER_LABEL_TAG;
label.font = [UIFont boldSystemFontOfSize:12];
label.textColor = [UIColor redColor];
[headerView addSubview:label];
}
label.text = [NSString stringWithFormat:#"Section %d", indexPath.section];
return headerView;
}

Related

UICollectionView distance between cells not changing

I am developing iOS app in which i got stuck at one point.
I am using horizontal collectionView, i want to reduce the spacing between two collectionViewCell, i have wrote the below code snippet but it doesn't change the spacing between the cells.
.h class
#property (strong, nonatomic) IBOutlet UICollectionView *CollectnVw;
.m class
- (void)viewDidLoad{
[_CollectnVw registerNib:[UINib nibWithNibName:#"FilterCustomCell" bundle:nil] forCellWithReuseIdentifier:#"collectionViewCell"];
_CollectnVw.backgroundColor = [UIColor clearColor];
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(100, 35)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[_CollectnVw setCollectionViewLayout:flowLayout];
[_CollectnVw setAllowsSelection:YES];
_CollectnVw.delegate=self;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [FilterNameArr count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"collectionViewCell" forIndexPath:indexPath];
UILabel *titleLabel = (UILabel *)[cell viewWithTag:96];
[titleLabel setText:[FilterNameArr objectAtIndex:indexPath.row]];
cell.layer.borderWidth=1.0f;
cell.layer.borderColor=[UIColor blueColor].CGColor;
return cell;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionView *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 50; // This is the minimum inter item spacing, Doesn't changing.....
}
I am able to see my cells but spacing between the cells not changing, i want zero spacing between the cells...
please help and thanks in advance
Finally problem has been solved by writing this,
flowLayout.minimumInteritemSpacing=0.0f;
flowLayout.minimumLineSpacing=0.0f;
The UICollectionViewFlowLayout exposes two properties itself; minimumInteritemSpacing which sets the spacing between items in the same row, and minimumLineSpacing which sets the spacing between lines of items in the grid. Have you tried just setting the property of your layout when you initialise it?
flowLayout.minimumInteritemSpacing = 0.0f;
click on collection view flow laytout and in size inspector change min spaceing between cell.
"IN Document Outline"

Increased memory allocation when calling CGAffineTransformMakeRotation

I have a collection view with the layout set to horizontal scrolling. Each header section contains a label which needs to be rotated 90 degrees
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableview = nil;
if (kind == UICollectionElementKindSectionHeader)
{
Collection *collection=self.collectionArray[indexPath.section];
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView" forIndexPath:indexPath];
headerView.tag=indexPath.section;
headerView.backgroundColor=[Settings getInstance].textColor;
UIImageView* expandView=(UIImageView*)[headerView viewWithTag:kExpandImage];
expandView.image=[UIImage imageNamed:[NSString stringWithFormat:#"expand_%#.png",[Settings getInstance].appBrand]];
UILabel* label=(UILabel*)[headerView viewWithTag:kCollectionLabel];
label.text=[NSString stringWithFormat:#"%#",collection.name];
label.backgroundColor=[Settings getInstance].textColor;
label.textColor=[Settings getInstance].backColor;
label.font=[UIFont fontWithName:#"HelveticaNeue-UltraLight" size:50];
label.transform = CGAffineTransformMakeRotation(-M_PI_2);
CGRect frame=label.frame;
frame.size.height=headerView.layer.frame.size.height;
frame.origin.y=headerView.layer.frame.origin.y;
label.frame=frame;
//add tap gesture to detect touch
HeaderTapRecognizer *singleTapRecogniser = [[HeaderTapRecognizer alloc] initWithTarget:self action:#selector(sectionTapped:)];
singleTapRecogniser.sectionIndexPath=indexPath;
singleTapRecogniser.delegate=self;
singleTapRecogniser.numberOfTouchesRequired = 1;
singleTapRecogniser.numberOfTapsRequired = 1;
[headerView addGestureRecognizer:singleTapRecogniser];
reusableview= headerView;
}
if (kind == UICollectionElementKindSectionFooter) {
UICollectionReusableView *footerview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"FooterView" forIndexPath:indexPath];
reusableview = footerview;
}
return reusableview;
}
When I run this through Instruments, I'm getting an increased memory allocation under GSEventRunModal. The problem is resolved by taking out this line of code
label.transform = CGAffineTransformMakeRotation(-M_PI_2);
All examples I've seen all use this method to rotate a label so unsure where I'm going wrong.
Any ideas are most welcome, thanks.
One thing to try would be applying the transformation BEFORE you add the text, background color, text color and font. That way you are only rotating an empty label, then subsequently filling it.

UICollectionViewCell is overlapped when scrolling

Following code is a very simple program which is used to display numbers from 1-10000 in the UICollectionView. It is displaying correctly without scrolling, but the cells are overlapped if you scroll down and scroll back the collection view.
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 10000;
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(100,30);
}
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier = #"cell_id";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
[label setText:[NSString stringWithFormat:#"%d", indexPath.item, nil]];
[cell.contentView addSubview:label];
return cell;
}
The problem here is that the label is being added to the view's cell repeatedly. The old label is not removed when the cell is reused and hence you see multiple numbers overlapped. the solution can be to remove the old label like this
for (UIView *view in cell.contentView.subviews) {
if ([view isKindOfClass:[UILabel class]]) {
[view removeFromSuperview];
}
}
before adding to the cell. However this will create performance problems when the number of subviews increase. You can create a custom cell with a label and then update its value. I haven't tried it but i believe it will work. Hope this helps
This worked for me in Swift 3:
Almost same solution as approved solution, note that I used
cell.subViews
instead of
cell.contentView.subViews
What's worked for me is:
for view in cell.subviews {
view.removeFromSuperview()
}
Set the cell layer anchorPointZ to row index in cellForItemAtIndexPath: method
cell.layer.anchorPointZ = CGFloat(indexPath.row)

How to programmatically add header on UICollectionView with UICollectionViewLayout

I have a UICollectionView in one of my viewcontroller. My collection view uses a subclass of UICollectionViewLayout (custom) to layout the cells. First thing, as soon as I select Layout as Custom in dropdown on Storyboard, option to select supplementary views goes away.
I tried doing that programatically as shown below, but none of the delegate methods are getting called.
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if (kind == UICollectionElementKindSectionHeader) {
UICollectionReusableView *reusableview = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView" forIndexPath:indexPath];
if (reusableview==nil) {
reusableview=[[UICollectionReusableView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
}
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
label.text=[NSString stringWithFormat:#"Recipe Group #%li", indexPath.section + 1];
[reusableview addSubview:label];
return reusableview;
}
return nil;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
CGSize headerSize = CGSizeMake(320, 44);
return headerSize;
}
In my viewDidLoad Method I have
[self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"HeaderView"];
Can anyone point me where I'm messing up?
You're passing in the incorrect view kind.
Your line registering the class:
[self.collectionView registerClass:[UICollectionReusableView class]
forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
withReuseIdentifier:#"HeaderView"];
Should be:
[self.collectionView registerClass:[UICollectionReusableView class]
forSupplementaryViewOfKind: UICollectionElementKindSectionHeader
withReuseIdentifier:#"HeaderView"];
Edit: Looks like your code is all using sectionFooter. Are you trying to programmatically add a header or a footer?
Found the issue, I was not returning attributes of my header in this UICollectionLayoutView method:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect
Check that you gave reference size for header in UICollectionViewFlowLayout
[flowLayout setHeaderReferenceSize:CGSizeMake(320, 50)];
and for footer
[flowLayout setFooterReferenceSize:CGSizeMake(320, 50)];
Your delegate method for header reference size is wrong, you call footer method,referenceSizeForFooterInSection, as follow:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
CGSize headerSize = CGSizeMake(320, 44);
return headerSize;
}
Individually set HeaderReferenceSize will fix the header problem. But app will crash you keep the above method and return nil in viewForSupplementaryElementOfKind for Footer.
your check:
if (kind == UICollectionElementKindSectionFooter)
Your should check for: UICollectionElementKindSectionHeader
same for:
dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
I think you should call this in your viewdidload method:
[collectionViewFlowLayout setHeaderReferenceSize:CGSizeMake(self.collectionView.frame.size.width, 50)];

UICollectionView header position in horizontal scroll direction mode with flow layout

I have ios UICollectionView with Flow layout with horizontal scroll direction.
In this situation typical header position is on the left side of cells.
I want to make header on the top of section cells
Have you any idea how can I do this?
I solved the problem using DateFlowLayout.
See how I configured it in this other answer.
I think you can get what you need using standard behavior for the header.
Set it up (probably in viewDidLoad):
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.headerReferenceSize = CGSizeMake(self.collectionView.bounds.size.width, 30);
// other setup
[self.collectionView setCollectionViewLayout:flowLayout];
Then answer a header view:
#define MY_HEADER_LABEL_TAG 128
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
UICollectionElementKindSectionHeader withReuseIdentifier:#"SectionHeader" forIndexPath:indexPath];
UILabel *label = (UILabel *)[headerView viewWithTag:MY_HEADER_LABEL_TAG];
if (!label) {
label = [[UILabel alloc] initWithFrame:CGRectInset(headerView.bounds, 5, 5)];
label.tag = MY_HEADER_LABEL_TAG;
label.font = [UIFont boldSystemFontOfSize:12];
label.textColor = [UIColor darkGrayColor];
[headerView addSubview:label];
}
label.text = [NSString stringWithFormat:#"Section %d", indexPath.section];
return headerView;
}

Resources