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"
Related
I have a UILabel in a collectionView header. The label is set to zero lines, word wrapping, and proper leading/trailing/top space constraints. If i DO NOT call [collectionView reloadData], the label expands properly to text with greater than two lines. Once reloadData is called, the label goes back to a single line...the second line disappears.
- (UICollectionReusableView *) collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
if (kind == UICollectionElementKindSectionHeader) {
header = (viewRollHeader *) [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"header" forIndexPath:indexPath];
header.rollTitle.text = [self.roll objectForKey:#"title"];
header.rollDescription.text = [self.roll objectForKey:#"info"];
[header.cancelButton addTarget:self action:#selector(exit) forControlEvents:UIControlEventTouchUpInside];
return header;
}
return [UICollectionReusableView new];
}
- (CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section{
if (section == 0) {
CGRect labelRect = [[self.roll objectForKey:#"title"]
boundingRectWithSize: header.rollTitle.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName : [UIFont fontWithName:#"Arial-BoldMT" size:32.0f]}
context:nil];
return CGSizeMake([[UIScreen mainScreen]bounds].size.width, (174.0f + labelRect.size.height));
}
return CGSizeZero;
}
collectionView:viewForSupplementaryElementOfKind:atIndexPath: is used for the header or footer of the entire collectionView, while collectionView:referenceSizeForHeaderInSection: is used for the header of a specific section of the collectionView
to make sure the size of the header stays consistent and respects your constraints, you'll need to call [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout setHeaderReferenceSize:CGSizeMake(width, height)] once the flowlayout is instantiated
Use label setter property inside delegate method where you configure each cell.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
//add label property here
return cell;
}
After reloading, it calls this method again to configure the label.
Try setting the preferredMaxLayoutWidth to the label
self.label.preferredMaxLayoutWidth = 300;
I'm create UICollectionView programmatically to uiview (i use single view). like this
UICollectionViewFlowLayout *CATLayout=[[UICollectionViewFlowLayout alloc]init];
CATLayout.minimumInteritemSpacing = 2.0f;
CATLayout.minimumLineSpacing = 2.0f;
CATLayout.scrollDirection = UICollectionViewScrollDirectionVertical;
CATLayout.sectionInset = UIEdgeInsetsMake(1.0f, 1.0f, 1.0f, 1.0f);
self.ColStickersListView=[[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, StickersListView.frame.size.width, StickersListView.frame.size.height) collectionViewLayout:CATLayout];
self.ColStickersListView.delegate=self;
self.ColStickersListView.dataSource=self;
self.ColStickersListView.tag=2;
[self.ColStickersListView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"CollStickersList"];
[self.ColStickersListView setBackgroundColor:[UIColor clearColor]];
[StickersListView addSubview:ColStickersListView];
and
UICollectionViewCell *cell = [ColStickersListView dequeueReusableCellWithReuseIdentifier:#"CollStickersList" forIndexPath:indexPath];
// for background selected
NSString *imageName=anObject;
NSString *filename=[NSString stringWithFormat:#"%#/Stickers/List/%#",[appDel DocsPath],imageName];
NSLog(#"%#",filename);
cell.backgroundColor=[UIColor clearColor];
UIImage *image=[UIImage imageNamed:filename];
UIImageView *photoView=[[UIImageView alloc]initWithFrame:CGRectMake(StickersListPadding,StickersListPadding,StickersListThumbSize-(StickersListPadding*2),StickersListThumbSize-(StickersListPadding*2))];
photoView.image=image;
photoView.contentMode=UIViewContentModeScaleAspectFit;
photoView.userInteractionEnabled = YES;
[cell.contentView addSubview:photoView];
return cell;
it's work perfect for display image to cell.
Problem !!
if scroll page to bottom and scroll return to top again that image in cell it's overlap.
How to fix it.!!! (Programmatically only with single view)
I suspect because you aren't setting the frame on the UIImageView it is deriving its size from the image that is being set on it. So in some cases it might overflow its parent view -> the cell in this case.
I suggest you setup some constraints on the UIImageView, this can be done programmatically.
So try to set left, right, top and bottom constraints on the UIIMageView so that it stays within the bounds of the cell
During scroll
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath is beeing called repeatively..
the means your are adding UIImageView *photoView repeatedly to cell.contentView
UIImageView *photoView=[[UIImageView alloc]initWithFrame:CGRectMake(StickersListPadding,StickersListPadding,StickersListThumbSize-(StickersListPadding*2),StickersListThumbSize-(StickersListPadding*2))];
//codes..
[cell.contentView addSubview:photoView];
doing something like this prevent that:
UICollectionViewCell *cell = [ColStickersListView dequeueReusableCellWithReuseIdentifier:#"CollStickersList" forIndexPath:indexPath];
if (cell == nil)
{
UIImageView *photoView=[[UIImageView alloc]initWithFrame:CGRectMake(StickersListPadding,StickersListPadding,StickersListThumbSize-(StickersListPadding*2),StickersListThumbSize-(StickersListPadding*2))];
// codes...
[cell.contentView addSubview:photoView];
}
Another way of solving this is by creating a custom collection cell:
// CustomCollectionCell.h
#interface YourCollectionCell : UICollectionViewCell
#property (nonatomic) UIImageView *photoView;
#end
// CustomCollectionCell.m
#implementation YourCollectionCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// and setting up you imageview here
self.photoView=[[UIImageView alloc]initWithFrame:YourRect];
self.photoView.contentMode=UIViewContentModeScaleAspectFit;
self.photoView.userInteractionEnabled = YES;
[self.contentView addSubview:self.photoView];
}
return self;
}
and using it like:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CustomCollectionCell *cell = (CustomCollectionCell *)[ColStickersListView dequeueReusableCellWithReuseIdentifier:#"CollStickersList" forIndexPath:indexPath];
cell.photoView.image=image;
return cell;
}
Hope i've helped you, happy coding.. Cheers & Good night!
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;
}
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)
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)];