Reputation: 39283
My cells are squares and look good at any size. I am looking to find the largest size for cells so that displaying all of them will not require scrolling.
And by example, this screen shot is great for 3 players, but kicking it up to 12 players makes them scroll out of bounds, which is to be avoided.
Is there a way to accomplish this?
Upvotes: 2
Views: 2042
Reputation: 39283
Based on rdelmar's code above with all the finesse taken out. Brute force calculation ensure the correct answer in some edge cases the other answer fails at.
Uses binary search for efficiency.
// Make the cells fit
override func viewDidLayoutSubviews() {
var highestWorking = 0
var lowestNotWorking = 9999
while lowestNotWorking > highestWorking + 1 {
let currentTest = (highestWorking + lowestNotWorking) / 2
let cols = Int(playerPhotoCollectionView.frame.size.width + 10) / (currentTest + 10)
let rows = Int(playerPhotoCollectionView.frame.size.height + 10) / (currentTest + 10)
if cols * rows >= game.numberOfPlayers {
highestWorking = currentTest
} else {
lowestNotWorking = currentTest
}
}
let size = CGSize(width: CGFloat(highestWorking), height: CGFloat(highestWorking))
(self.playerPhotoCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = size
super.viewDidLayoutSubviews()
}
Upvotes: 2
Reputation: 39283
Here is a new solution in Swift. It uses binary search for better performance.
Assumptions:
currentTest
as the longest size and edit the rows
or cols
, which ever is the smaller aspect size)override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var highestWorking = 0
var lowestNotWorking = 9999
while lowestNotWorking > highestWorking + 1 {
let currentTest = (highestWorking + lowestNotWorking) / 2
let cols = Int(playerPhotoCollectionView.frame.size.width + 10) / (currentTest + 10)
let rows = Int(playerPhotoCollectionView.frame.size.height + 10) / (currentTest + 10)
if cols * rows >= self.playerCount {
highestWorking = currentTest
} else {
lowestNotWorking = currentTest
}
}
let size = CGSizeMake(CGFloat(highestWorking), CGFloat(highestWorking))
(self.playerPhotoCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = size
}
Upvotes: 0
Reputation: 104082
Solving this problem is mostly algebra with a little logic thrown in. First, you need to get the aspect ratio of the collection view, so you know whether you should have more rows or more columns. Once you know that, you can calculate the itemsPerRow, and the numberOfRows. Since you want your cells to be squares, you need to use the smaller of the two sizes that you calculate for how many items will fit in a row or column. When you calculate the sizes, you need to take in to account the minimum spacings in each direction. Here is a little test project that shows how I did it.
#define PLAYERS 4.0
#import "ViewController.h"
@interface ViewController ()
@property (weak,nonatomic) IBOutlet UICollectionView *collectionView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout setMinimumInteritemSpacing:10];
[(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout setMinimumLineSpacing:10];
}
-(void)viewDidLayoutSubviews {
CGFloat aspectRatio = (self.collectionView.bounds.size.height/self.collectionView.bounds.size.width);
int itemsPerRow = (aspectRatio > 1)? floorf(pow(PLAYERS,.5)) : ceilf(pow(PLAYERS,.5));
if (aspectRatio >1) {
itemsPerRow = itemsPerRow - (floorf(aspectRatio) - 1);
}else{
itemsPerRow = itemsPerRow - (floorf(1/aspectRatio) - 1);
}
int numberOfRows = ceilf(PLAYERS/itemsPerRow);
CGFloat width = (self.collectionView.bounds.size.width - ((itemsPerRow - 1) *10)) / itemsPerRow;
CGFloat height = (self.collectionView.bounds.size.height - ((numberOfRows - 1) *10)) / numberOfRows;
CGFloat dim = MIN(width, height);
[(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout setItemSize:CGSizeMake(dim,dim)];
[self.collectionView reloadData];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return PLAYERS;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
return cell;
}
Upvotes: 1