I was trying to remove the space between UICollectionView and this is the screenshots from device
I am really trying to avoid those spaces(blue color) and i have tried following codes
This is my collectionview delegate
#pragma mark <UICollectionViewDataSource>
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 30;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
return cell;
}
First I tried this one, and its not working
- (void)viewDidLoad {
[super viewDidLoad];
UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cell.frame.size.width, cell.frame.size.height);
flow.scrollDirection = UICollectionViewScrollPositionCenteredVertically;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
}
and I tried this one also, its not working
#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 5.0;
}
Please help me to fix this.
So there is properties and methods can limit the minimum space, such as minimumInteritemSpacingForSectionAtIndex
However it is just the 'minimum space' not always the max space.
This what I am using: borrow from Cell spacing in UICollectionView
Override standard flow layout:
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *answer = [super layoutAttributesForElementsInRect:rect];
for(int i = 1; i < [answer count]; ++i) {
UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
NSInteger maximumSpacing = 4;
NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
CGRect frame = currentLayoutAttributes.frame;
frame.origin.x = origin + maximumSpacing;
currentLayoutAttributes.frame = frame;
}
}
return answer;
}
maximumSpacing could be set to any value you prefer
From storyboard also you can set the spacing attributes. Select your collection view - select size inspector tab, there you can adjust minimum spacing for for cells or for lines.
And you can adjust section insets also.
flow.sectionInset = UIEdgeInsetsMake(1, 1, 1, 1);
Use sectionInset for your UICollectionViewFlowLayout in viewdidload.
See my answer on how to adjust UICollectionView width (using AutoLayout constraint) to fit all cells perfectly without any spacing between them.
Related
I'm creating Grid View with UICollectionView and want to scroll it by paging.
Now I have a problem. The offset of grid gradually shift by paging scroll.
I want to fit the left top of next page cell to that of screen.
My code is like below,
ViewController.m
- (void)loadView
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
self.view = [[GridView alloc] initWithLayout:layout];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBarHidden = YES;
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
GridView.m
#define GRID_SPACE (20)
- (id)initWithLayout:(UICollectionViewFlowLayout *)layout
{
self = [super initWithFrame:CGRectZero collectionViewLayout:layout];
if (self) {
self.pagingEnabled = YES;
self.backgroundColor = UIColor.redColor;
self.delegate = self;
self.dataSource = self;
[self registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass([UICollectionViewCell class])];
}
return self;
}
#pragma mark -
#pragma mark UICollectionViewDelegate
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGSize selfSize = self.frame.size;
return CGSizeMake( (selfSize.width - GRID_SPACE) / 2, (selfSize.height - GRID_SPACE) / 2 );
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return GRID_SPACE;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return GRID_SPACE;
}
I'd appreciate if you would provide me a good solution.
Thank you.
The page size of an UIScrollView (which UICollectionView inherits from) is the size of it's viewport, so to make it work you need to include the height of the red border at the top. If you don't want to show the border at top or bottom, then you can let the UICollectionView stretch under another element or under the top of the display if it is aligned at the top.
LGP's answer resolved my problem. Resolved code I added to my GridView.m is below,
Add the length of grid item to the height of CollectionView, because the theight is the length of Paging Scroll.
And more, you need to set the length of grid item as bottom of CollectionView insets.
In GridView.m
- (void)layoutSubviews
{
[super layoutSubviews];
CGSize parentSize = self.superview.frame.size;
self.frame = CGRectMake(0, 0, parentSize.width, parentSize.height + GRID_SPACE);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, GRID_SPACE, 0);
}
I have a UICollection view which looks like this (see two purple and blue borders):
On iOS 10 there is no header/whitespace, but on iOS11 there is. I've tried everything mentioned here: How can I enable/disable section headers in UICollectionView programmatically?
And my code currently looks like this:
- (void) viewDidLoad
{
[super viewDidLoad];
autocompleteLayout = [[SQLProAutocompleteFlowLayout alloc] init];
autocompleteLayout.headerReferenceSize = CGSizeZero;
autocompleteCollectionView = [[UICollectionView alloc] initWithFrame: CGRectZero
collectionViewLayout: autocompleteLayout];
autocompleteCollectionView.insetsLayoutMarginsFromSafeArea = NO;
[self.view addSubview: autocompleteCollectionView];
// removed layout code (leftAnchor, rightAnchor, topAnchor, bottomAnchor).
autocompleteCollectionView.delegate = self;
autocompleteCollectionView.dataSource = self;
// Removed nib register code
self.view.layer.borderColor = [UIColor redColor].CGColor;
self.view.layer.borderWidth = 1;
autocompleteCollectionView.layer.borderColor = [UIColor blueColor].CGColor;
autocompleteCollectionView.layer.borderWidth = 2;
}
- (CGSize) collectionView: (UICollectionView *) collectionView
layout: (UICollectionViewLayout *) collectionViewLayout
referenceSizeForHeaderInSection:(NSInteger)section
{
return CGSizeZero;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
referenceSizeForFooterInSection:(NSInteger)section
{
return CGSizeZero;
}
And my FlowLayout looks like this:
- (void) setupLayout
{
self.minimumInteritemSpacing = 0;
self.minimumLineSpacing = 0;
self.scrollDirection = UICollectionViewScrollDirectionVertical;
} // End of setupLayout
- (void) prepareLayout
{
[super setItemSize: [self itemSize]];
[super setSectionInset: [self sectionInset]];
self.minimumLineSpacing = 0;
[super prepareLayout];
} // End of prepareLayout
- (CGFloat) itemWidth
{
return self.collectionView.frame.size.width;
}
- (CGSize) itemSize
{
CGSize result = CGSizeMake(self.collectionView.frame.size.width,
rowHeight);
return result;
}
- (void) setItemSize:(CGSize)itemSize
{
self.itemSize = CGSizeMake(self.collectionView.frame.size.width,
rowHeight);
}
- (CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
{
return CGPointZero;
}
I have also verified that the UICollectionView's contentInset is zero'd out.
What am I missing? Why does my UICollectionView still have whitespace?
In iOS 11, there have been some changes to UIScrollView.
Try setting the contentInsetAdjustmentBehavior property
collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
Try this:
self.automaticallyAdjustsScrollViewInsets = false
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 0;
}
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(-25,0,0,0); // top, left, bottom, right
}
I am using third party UiCollection View KRLCollectionViewGridLayout.
In this I have the following issue attached in screen shot.
See the above screen shot. There is an extra space in collectionview cell.
My Question is how to remove these extra space in collection cell and also how to add separator between two cell?
Here is my Code:
- (KRLCollectionViewGridLayout *)layout
{
return (id)self.collectionView.collectionViewLayout;
}
- (IBAction)changeColumnsTapped:(id)sender {
[[[UIActionSheet alloc] initWithTitle:#"Choose how many columns"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:#"1",#"2", nil]
showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
self.layout.numberOfItemsPerLine = [[actionSheet buttonTitleAtIndex:buttonIndex] integerValue];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UISearchBar *searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, -44, self.view.frame.size.width, 44.0)];
[self.collectionView addSubview:searchBar];
[self.collectionView setContentInset:UIEdgeInsetsMake(44, 0, 0, 0)];
self.layout.numberOfItemsPerLine = 1;
self.layout.aspectRatio = 1;
self.layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
self.layout.interitemSpacing = 10;
self.layout.lineSpacing = 10;
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = NO;
// Register cell classes
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
//recipePhotos = [NSMutableArray arrayWithObjects:#"image1.png",#"image2.png",#"image3.png", nil];
recipePhotos = [NSMutableArray arrayWithObjects:#"image1.png", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [recipePhotos count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell1" forIndexPath:indexPath];
//cell.contentView.backgroundColor = [UIColor blueColor];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
recipeImageView.image = [UIImage imageNamed:[recipePhotos objectAtIndex:indexPath.row]];
cell.layer.borderWidth = 0.5;
return cell;
}
I'm the author of this layout. As it stands now, it looks like you're using the default value of the layout's aspectRatio property of 1/1 which is what is in charge of sizing the cells. Unfortunately this layout does not yet support dynamically-sized cells, but I may do so in the future. If you know how high your cells are intended to be relative to their width, you can set the aspect ratio accordingly. an aspect ratio of 2 would mean it's twice as long as it is tall, and an aspect ratio of 0.5 would mean it's 1/2 as long as it is tall. You probably want some number greater than 1 for your ratio to decrease the spacing.
If that doesn't give you the effect you want, you may need to switch to UICollectionViewFlowLayout instead which gives you precise control over the size of cells.
Try This. Check This Link Cell spacing in UICollectionView
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 2.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(0,0,0,0); // top, left, bottom, right
}
Add UICollectionViewDelegateFlowLayout delegate in you interface
and ipmplement
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return IPAD ? CGSizeMake(75, 75) : CGSizeMake(55, 55);
}
And change size as per your requirement.
I need to create a UICollectionView cells with dynamic heights according to each cell's image view height. I have created a subclass from UICollectionViewFlowLayout to implement the desired behaviour as follows:
#define numColumns 2
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (attributes.representedElementKind == nil) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* currentItemAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item < numColumns) {
CGRect frame = currentItemAttributes.frame;
frame.origin.y = 5;
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
NSIndexPath* indexPathPrev = [NSIndexPath indexPathForItem:indexPath.item-numColumns inSection:indexPath.section];
CGRect framePrev = [self layoutAttributesForItemAtIndexPath:indexPathPrev].frame;
CGFloat YPointNew = framePrev.origin.y + framePrev.size.height + 10;
CGRect frame = currentItemAttributes.frame;
frame.origin.y = YPointNew;
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
And in the collection view controller delegate flow layout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
float imageHeight = [[(Product *)self.products[indexPath.row] image] height];
float imageWidth = [[(Product *)self.products[indexPath.row] image] width];
float ratio = 150.0/imageWidth;
return CGSizeMake(150, ratio*imageHeight);
}
Cell implementation
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ProductCell *cell = (ProductCell *)[self.collectionView dequeueReusableCellWithReuseIdentifier:#"ProductCell" forIndexPath:indexPath];
....
[cell.imageView setImageWithURL:[NSURL URLWithString:[[(Product *)self.products[indexPath.row] image] url]]];
return cell;
}
All the cells showed up as expected, but the content view was too long as shown.
I think I have to implement the method -(CGSize)collectionViewContentSize to get the correct contentSize, but I don't know how to calculate the actual height of the collection view
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"];