10

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

StoryboardView

2) Result With Four Cell's

Result With Four Cell's

3)when Number of Cell Increase

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];
 }
Mayank Patel
  • 3,612
  • 9
  • 34
  • 52
Badal Shah
  • 7,255
  • 2
  • 27
  • 59

5 Answers5

0

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;

Loegic
  • 3,160
  • 18
  • 32
  • can you explain beat more ? what should (means which size)i have to return in switchcase ? and one more things according to device screen size-square position will be misplaced when device changed . so i have to make separate condition for all device ? thanks. – Badal Shah Sep 15 '15 at 04:42
  • thanks for your replay . but by changing device it will autoarrange square or i need to set condition for each device ? – Badal Shah Sep 15 '15 at 10:00
  • No it will arrange depending on the frame of the collectionView, so if it's wider, the cell will be wider and vice versa – Loegic Sep 15 '15 at 10:12
  • i have tried it which you said but due to screen size in iphone 5s and iphone 4s it is not autoarrange correctly . – Badal Shah Sep 15 '15 at 10:17
  • you mean vertically or horizontally ? – Loegic Sep 15 '15 at 10:35
  • Vertically 1 cell down . – Badal Shah Sep 15 '15 at 10:42
  • Yes, so you should divide more on iPhone 4. – Loegic Sep 15 '15 at 10:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89672/discussion-between-badal-shah-and-loegic). – Badal Shah Sep 15 '15 at 11:07
0

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.

Community
  • 1
  • 1
pkc456
  • 7,998
  • 34
  • 45
  • 99
0

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.

Rich Tolley
  • 3,732
  • 1
  • 27
  • 38
ngoa
  • 410
  • 2
  • 13
0

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.

PT Vyas
  • 716
  • 9
  • 28
0

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

iOS Geek
  • 4,477
  • 1
  • 7
  • 28