I am working on collection-view Based project on which Numberofitem will be changed and increase according to user's click on Particular Index. all Works perfectly in my project but i am not able to set Cell size according to number of cell's in collection-view.Moreover collectionview will not be scrollable all cell fix in view with resize.
Here i have attached all the image's .
1) Storyboard View
2) Result With Four Cell's
3)when Number of Cell Increase
Currently i done setup of my cell by this way with following code. but i want to set that, if there is four cell in collection-view then the size of each cell increases and fit according to collection-view and device size (iphone 5s , iphone 6 , iphone 6plus)
Here is my Try,
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section{
return 5.0;
}
-(CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section{
return 5.0;
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
////@property NSInteger count;////
if (_count == 0) {
// width = ((width - (span*5))/4);
// return CGSizeMake(self.view.frame.size.width/4, self.view.frame.size.height/4);
return CGSizeMake(self.view.frame.size.width/2.5, self.view.frame.size.height/5);
}
if (_count == 1 || _count == 2)
{
return CGSizeMake(self.view.frame.size.width/2.5, self.view.frame.size.height/5);
// return CGSizeMake(100.0, 100.0);
}
if ( _count == 3 || _count == 4 || _count == 5)
{
// return CGSizeMake(100.0, 100.0);
return CGSizeMake(self.view.frame.size.width/3.5, self.view.frame.size.height/6.5);
}
if ( _count == 6 || _count == 7 || _count == 8 || _count == 9)
{
//return CGSizeMake(90.0, 90.0);
return CGSizeMake(self.view.frame.size.width/4, self.view.frame.size.height/8);
}
if ( _count == 10 || _count == 11 || _count == 12 || _count == 13 || _count == 14)
{
// return CGSizeMake(80.0, 80.0);
return CGSizeMake(self.view.frame.size.width/4, self.view.frame.size.height/8);
}
if ( _count == 15 || _count == 16 || _count == 17 || _count == 18 || _count == 19 || _count ==20)
{
//return CGSizeMake(70.0, 70.0);
return CGSizeMake(self.view.frame.size.width/4.75, self.view.frame.size.height/9.5);
}
if (_count ==21 || _count == 22 || _count == 23 || _count == 24 || _count == 25 || _count == 26 || _count == 27) {
// return CGSizeMake(60.0, 60.0);
return CGSizeMake(self.view.frame.size.width/6, self.view.frame.size.height/12);
}
if (_count ==28 || _count == 29 ) {
// return CGSizeMake(50.0, 50.0);
return CGSizeMake(self.view.frame.size.width/6.25, self.view.frame.size.height/12.5);
}
else
return CGSizeMake(0, 0);
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return itemincollectionview.count;
}
Note:-
I have also tried this all Method.
- (void)viewDidLayoutSubviews
{
self.automaticallyAdjustsScrollViewInsets = NO;
[self.collectionView layoutIfNeeded];
NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
NSIndexPath *nextItem = [NSIndexPath indexPathForItem:_setRandomIndex inSection:currentItem.section];
[self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
[self.collectionView.collectionViewLayout invalidateLayout];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self.view layoutIfNeeded];
}
As far as I understand, you want to replicate the layout of this test.
You need to understand better how UICollectionView
works like here
You will have to change the number of items in your UICollectionView
in this delegate method:
- (NSInteger)numberOfItemsInSection:(NSInteger)section;
Here, you want to return 4 at the beginning of the test, then 4*2, 4*2*2, and so on. This will gives you the correct number of item.
Then the layout. you should have multiple values for it, as you don't want the same space between your elements as the beginning and at the end. I would go for reducing the space as the number of items grows.
You need to be careful with the spacing, because it can cause a cell to be forced in the next line
You already did a great job by dividing the frame to get the maximum height & width of a cell, but your
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
Method is really messy.
As you will not have an unlimited number of items in your UICollectionView
, you can use a switch statement
, and in each switch you return the computed CGSize
of the cell.
For example, you can use it like this:
switch (numberOfHorizontalItems) {
case 2:
return CGSizeMake(self.collectionView.frame.size.width/2.5,self.collectionView.frame.size.width/2.5);
break;
case 4:
return CGSizeMake(self.collectionView.frame.size.width/4.5,self.collectionView.frame.size.width/4.5);
break;
case 8:
CGSizeMake(self.collectionView.frame.size.width/8.5,self.collectionView.frame.size.width/8.5);
break;
(And so on)
default:
break;
}
You should note that the computed CGSize
displayed here have to incorporate the spacing / merging between the items
You also don't need viewWillLayoutSubviews
and viewDidLayoutSubviews
, you just need to call [self.collectionView reloadData]
when the user tapped a cell (or in the method handling the logic after an user tapped a cell)
Finally, if you don't want the UICollectionView
to be scrollable, just set the property self.collectionView.scrollEnabled = NO;
Follow this blog link which illustrate in very easy manner with example code:-
http://www.fantageek.com/1468/ios-dynamic-table-view-cells-with-varying-row-height-and-autolayout/
The upper link is for table view but in the same manner you can work on collection view and achieve your desired result.
Note: It is all about content hugging vs content compression resistance priority.
Use this GitHub CHTCollectionViewWaterfallLayout is a subclass of UICollectionViewLayout, and it trys to imitate UICollectionViewFlowLayout's usage as much as possible.
This layout is inspired by Pinterest. It also is compatible with PSTCollectionView.
So I am adding the answer in swift but this solution only works assuming you have a min width value.
/**
Calculates the CollectionView Cell Size when the parent view is loaded. It happens only once per VC Lifecycle.
- returns: `width` - The cell width calculated from the current screen size. <p/> `height` - The cell height, which is fixed for now.
*/
private class func getCellSize() -> (size: CGSize) {
var cellWidth: CGFloat, cellHeight: CGFloat
//Notes: CellSpacing you want to have
let CellSpacing: CGFloat = 5
// Notes: Minimum Cell Width that renders for all the screens
let MinCellWidth:CGFloat = 130
let screenWidth: CGFloat = UIScreen.mainScreen().bounds.size.width
let numberOfCellsPerRow: Int = Int((screenWidth + CellSpacing) / (MinCellWidth + CellSpacing))
let totalSpaceTaken: Int = (Int(MinCellWidth + CellSpacing) * numberOfCellsPerRow)
let remainingWidth = Int(screenWidth + CellSpacing) - totalSpaceTaken
cellWidth = MinCellWidth + CGFloat((remainingWidth/numberOfCellsPerRow))
//Now calculate the height based on the Width:Height Ratio.
// Assuming it is 1:1.5
cellHeight = cellWidth * 1.5
return CGSizeMake(cellWidth, FixedCellHeight)
}
This can be converted to Objective-C very easily. All we are doing here is getting the screen width and checking how many cells can we fit in and fit them with the right cell spacing.
Note: You only need to call getCellSize() method once and can use the same CGSize in the below method.
//In your viewDidLoad
CGSize cellSize = [self getCellSize];
//In this function you pass the property you initialised above
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return self.cellSize;
}
Note: This work only if your collectionView.width = viewController.width
i.e, your collectionView width is hugging the view controller, or collectionView size is equal screen size like how it was asked in the question.
Everything in your project is fine just you need to add a new delegate method as follows:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(15, 20, 20, 20);
}
Vary this method insets according to number of counts of you have. inset setting will be common for:
self.view.frame.size.width/2.5
and different for:
self.view.frame.size.width/3.5
hence the extra spacing issue will be solved