I'm trying to create a UICollectionView with 3 images per row.
For the start i used this code:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(110, 110);
}
And it's looking good but it only fits the iPhone X screen:
Then i tried to use this code so it will put 3 cells per row:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth / 3.0;
CGSize size = CGSizeMake(cellWidth, cellWidth);
return size;
}
But then the view is starting looking different:
This is the cell initialize method:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"TrendingCell";
TrendingCell *cell = (TrendingCell*)[collection dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
TrendingItem * item = [[[TrendingRep sharedTrending] trendingArray] objectAtIndex:indexPath.row];
cell.text.text = item.title;
cell.image.layer.cornerRadius = cell.image.frame.size.width / 2;
cell.image.clipsToBounds = YES;
[cell.image sd_setImageWithURL:[NSURL URLWithString:item.imageUrl]
placeholderImage:nil
options:SDWebImageProgressiveDownload
completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
[cell.progressView setHidden:NO];
}];
return cell;
}
Any idea what can be the issue with the view?
This looks like you're not taking into account the layout's minimumInteritemSpacing. The formula to calculate the item's width should be
float cellWidth = (screenWidth - 2.0 * minimumInteritemSpacing) / 3.0;
You have to provide minimum spacing between the collection View cell. You
are using collectionviewLayout, So you have to provide minimum spacing like below.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(collectionView.frame.size.width/3 - 10, collectionView.frame.size.width/3)
}
Here You can provide minimum spacing (like 10) between cells programmatically.
Related
I had an application in which I am taking the width of the collection view cell as:
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(20, 20,20,20);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenRect = collection.frame;
CGFloat screenWidth = screenRect.size.width;
float cellWidth = screenWidth / count;
}
But now I want on that count the width of the cell needs to be dependent on one parameter, like:
NSDictionary *dict=[arr objectAtIndex:indexPath.item];
float duration=([[dict valueForKey:#"duration"]floatValue]);
If duration is 45 then it needs to take 45% of the screen width and like that. Can anybody help me on This when i am trying screenWidth * (duration/100.0) it is looking like this
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect screenRect = collection.frame;
CGFloat screenWidth = screenRect.size.width;
NSDictionary *dict=[arr objectAtIndex:indexPath.item];
float duration=([[dict valueForKey:#"duration"]floatValue]);
float cellWidth = duration / 100;
return CGSize(cellWidth, 60);
}
It helps you.
If You collectionview just consist of this cells, then i would recommend you to go with section approach.
multiple section for each item , and each section has only one row . By this approach there will be only one row in section and as you wanted even if row size is 10% or less.
keep size approach like below.
NSDictionary *dict=[arr objectAtIndex:indexPath.item];
float duration=([[dict valueForKey:#"duration"]floatValue]);
float cellWidth = screenWidth * (duration/100.0);
Actually i want to set button dynamically and title of button appear Dynamic i have try this and got width of Dynamic content but am not setting cell width and height.
- (void)viewDidLoad {
[super viewDidLoad];
ContentArray = [[NSMutableArray alloc]init];
self.collectionview.delegate = self;
self.collectionview.dataSource =self;
self.collectionview.backgroundColor = [UIColor clearColor];
[ContentArray addObject:#"Planning"];
[ContentArray addObject:#"Resources"];
[ContentArray addObject:#"Human Resources"];
[ContentArray addObject:#"Agriculture"];
[ContentArray addObject:#"Resources management"];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return ContentArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
CollectionViewCell * Cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"CollectionViewCell"forIndexPath:indexPath];
[Cell.button setTitle:[ContentArray objectAtIndex:indexPath.row] forState:UIControlStateNormal];
return Cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
CGRect rect = [[ContentArray objectAtIndex:indexPath.row ] boundingRectWithSize:CGSizeMake(HUGE_VALF, 50) options:NSStringDrawingUsesFontLeading attributes:nil context:nil] ;
return CGSizeMake(rect.size.width, 50);
}
and output is like this
This is perfect i think if i make cell dynamic width and height, so please guide me through this.
pragma mark - GetHeightFromString
- (CGFloat)getTextHeightFromString:(NSString *)text ViewWidth:(CGFloat)width WithPading:(CGFloat)pading FontName:(NSString *)fontName AndFontSize:(CGFloat)fontSize
{
NSDictionary *attributes = #{NSFontAttributeName: [UIFont fontWithName:fontName size:fontSize]};
CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
//NSLog(#"rect.size.height: %f", rect.size.height);
return rect.size.height + pading;
}
Get height of the string from this method and add this to origional height of your cell or label or button whatever you want to use.
For example:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
YourCellClass *myCell = (YourCellClass*) [collectionView cellForItemAtIndexPath:indexPath];
CGFloat sizeFromString = [self getTextHeightFromString:itemObject.MenuDescription ViewWidth:myCell.frame.size.width WithPading:10 FontName:#"HelveticaNeue" AndFontSize:13];
return CGSizeMake(sizeFromString, sizeFromString);
}
You might need to change the height of inner label too, for this use same method in cellForItemAtIndexPath method of your UICollectionView.
Further more you can customize your own way.
In Swift 2.0:
Using a UICollectionViewFlowLayout enable cell auto-sizing.
The following code inside a UICollectionViewController subclass will enable auto-sizing for it’s flow layout.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
if let cvl = collectionViewLayout as? UICollectionViewFlowLayout {
cvl.estimatedItemSize = CGSize(width: 150, height: 75)
}
}
You can put different sizes in landscape & portrait mode try this -
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
// Adjust cell size for orientation
if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
return CGSizeMake(rect.size.width, 50);
}
return CGSizeMake(rect.size.width, 50);
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self.collectionView performBatchUpdates:nil completion:nil];
}
you can call invalidateLayout method on the .collectionViewLayout property of your UICollectionView
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[yourCollectionView.collectionViewLayout invalidateLayout];
}
You can try this...
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(width, height);
}
width, height are the dynamically calculated value
Thanks
I am working on Collectionvew with Paging . I am Successfully able to done collectionview with Paging. and It's work perfectly.
But the problem is i need only 10 cell in 1 page , then another 10 cell 2nd page and Next 10 cell in 3rd page. but I dont know How can i achive it when page changed.And i also want to change the title when page changed like , Easy ,Medium and Hard(Levels).
Currently i take 30 cells in collectionview . Here is my methods for collectionview ,
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
{
return kNumberOfCells;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"GameCollectionViewCell";
GameCollectionViewCell *cell = (GameCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
if (cell == nil)
{
NSArray *xib = [[NSBundle mainBundle] loadNibNamed:#"HomeCollectionViewCell" owner:self options:nil];
cell = [xib objectAtIndex:0];
}
cell.lblLevel.text=[NSString stringWithFormat:#"%d",indexPath.item+1];
cell.lblLevelPoints.text=#"points";
return cell;
}
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
float width = collectionView.frame.size.width/6.4;//120
float height = collectionView.frame.size.height/4;//120
return CGSizeMake(width,width);
}
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(8.0, 14.0, 5.0, 14.0);//TOP , LEFT ,BOTTOM ,RIGHT
}
Output Currently i am getting :-
There are two solutions :
Solution 1 :
You can take number of section 3. Each section with 10 items. With each section you have change current page of UIPageControl and change title too.
Solution 2:
Place PageControl in your view or set by Code.
Set UIScrollViewDelegate
In Collectionview-> cellForItemAtIndexPath (Method) add the
below code for calculate the Number of pages,
int pages =floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width);
[pageControl setNumberOfPages:pages];
Add the ScrollView Delegate method
pragma mark - UIScrollVewDelegate for UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = ImageCollectionView.frame.size.width;
float currentPage = ImageCollectionView.contentOffset.x / pageWidth;
if (0.0f != fmodf(currentPage, 1.0f))
{
pageControl.currentPage = currentPage + 1;
}
else
{
pageControl.currentPage = currentPage;
}
NSLog(#"finishPage: %ld", (long)pageControl.currentPage);
}
Reference Link :
Collectionview + Pagecontrol
Update:
There is one sample code also made by me on Github. It help you :
https://github.com/maniyarpayal/PagingWithCollectionView
try this delegate methods,
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake((self.view.frame.size.width / 5) , self.view.frame.size.height / 2);
}
- (NSUInteger)maximumNumberOfColumnsForCollectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
{
return 5;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
i have also same problem, then use the above methods its will working for me, hope its helpful.
you can use this delegate method but you have to customise according to your requirement because i did not mention distance between cells and x-origin .and you have to do minus those distance from view width. hope this will help you.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake((self.view.frame.size.width / 10) , self.view.frame.size.height / 2);
}
I have a view which contains UICollectionView that loads external cellnib file of UICollectionViewCell. I have the data showing properly just the way I want. I want to keep the cell height based on the textlabel inside it but I am not sure what am I missing in the code below. I have tried going through answers but it did not make much sense on how to tackle it. Please help. Thanks in advance.
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#" mycell" forIndexPath:indexPath];
NSString *string = cell.lblContact.text;
CGSize size = [self getLabelSize:string];
NSLog(#"%f and %f",size.width ,size.height);
return cell;
}
- (CGSize)getLabelSize:(NSString *)string {
UIFont *updatedFont = [UIFont fontWithName:#"myFont" size:18.0];
CGRect rect = [string boundingRectWithSize:(CGSize){maxWidth, CGFLOAT_MAX} options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName: updatedFont } context:nil];
return rect.size;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize retval = CGSizeMake(collectionView.frame.size.width, 75);
return retval;
}
- (UIEdgeInsets)collectionView: (UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
I found the solution. I created a string in sizeForItemAtIndexPath that was getting a value out from the same place as cell.lblContact.text.
MyObject *mc = (MyObject *) [contactArray objectAtIndex:indexPath.row];
NSString *myString = mc.contactName;
CGSize size = [self getLabelSize:myString];
NSLog(#"%#", myString);
NSLog(#"%f", size.height);
if (myString.length > 25) {
CGSize retval = CGSizeMake(collectionView.frame.size.width, size.height);
[collectionView layoutIfNeeded];
return retval;
} else {
CGSize retval = CGSizeMake(collectionView.frame.size.width, 75);
return retval;
}
You retrieve the size of the label, but it looks like you are using a different CGSize to size the label. Instead of CGSizeMake(collectionView.frame.size.width, 75), try keeping a reference to the size of the label and using that as the return value:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MyCollectionViewCell *cell = (MyCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#" mycell" forIndexPath:indexPath];
NSString *string = cell.lblContact.text;
self.labelSize = [self getLabelSize:string];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.labelSize;
}
EDIT
Have you tried accessing the frame of the label and storing it?
self.labelSize = CGSizeMake(self.myCell.frame.size.width, self.myCell.frame.size.height);
I'm trying to adjust the cell heights to fit the UIImages, the problem is it does not seem like the UIImage is filling the collectionView cell. As you can see on this
Image: http://oi61.tinypic.com/98d3zd.jpg
It seems like the cell adjusted, but the image is not filled correctly to fill the cell?
cellheights
First I've created a loop which calculate the new height if the cellWidth is 140, which is the case allways.
for (int i = 0; i < [homesDic count]; i++) {
UIImage *originalImage = [[homesDic objectAtIndex:i] objectForKey:#"image"];
CGFloat originalHeight = originalImage.size.height;
CGFloat originalWidth = originalImage.size.width;
CGFloat wantedWidth = 140;
float wantedHeight = (originalHeight*wantedWidth)/originalWidth;
[_cellHeights addObject:#(wantedHeight)];
}
Then I insert a imageView in to the collectionView cell and set the frame and set cell height equal to the imageheight from the cellHeights array.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
FRGWaterfallCollectionViewCell *waterfallCell = [collectionView dequeueReusableCellWithReuseIdentifier:WaterfallCellIdentifier indexPath];
waterfallCell.lblTitle.text = [NSString stringWithFormat: #"Item %d", indexPath.item];
waterfallCell.bottomView.backgroundColor = [UIColor colorWithRed:0.184 green:0.192 blue:0.196 alpha:0.7];
waterfallCell.homeImage.image = [[homesDic objectAtIndex:indexPath.item] objectForKey:#"image"];
waterfallCell.homeImage.frame = CGRectMake(0, 0, [self.cellHeights[indexPath.item] floatValue], waterfallCell.frame.size.width);
return waterfallCell;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView
layout:(FRGWaterfallCollectionViewLayout *)collectionViewLayout
heightForItemAtIndexPath:(NSIndexPath *)indexPath {
return [[self.cellHeights objectAtIndex:indexPath.item] floatValue];
}
To set up cell size you should use collectionView:layout:sizeForItemAtIndexPath method, try this:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// Get reference to your image base on indexPath here (I assume you have one section and indexPath.row refer to right image) adjust if needed:
UIImage *originalImage = [[homesDic objectAtIndex: indexPath.row] objectForKey:#"image"];
CGSize imgSize = originalImage.size;
//Adjust if needed
imgSize.height += 20;
imgSize.width += 20;
return imgSize;
}
if you need spacing between the cells, headers, and footers, use this method:
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsMake(20, 10, 20, 10);
}
Hope this is what you are looking for