UICollectionView With Variable Cells Displaying Them Weirdly - ios

I have a UICollectionView that I want to have cells that are always half the height of the display and sometimes half of the width but sometimes 1/4th the width. In the picture below I have drawn what the UICollectionView is displaying. In landscape I am telling it to display a 1/4th width cell and then a half cell and then another 1/4th and that repeats again. In theory there should be 6 cells on the screen, but the cells end up all scattered. I can't figure out what I'm doing wrong. If I have every cell one size it works fine, just with different sizes this happens.
This is what happens:
This is what I want to happen:
Heres my code for setting up the layout and altering the individual cell sizes:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if ([bigCells containsObject: indexPath.row]) {
return CGSizeMake((CollectionView.frame.size.width/2), (CollectionView.frame.size.height/2));
} else {
return CGSizeMake((CollectionView.frame.size.width/4), (CollectionView.frame.size.height/2));
}
}
- (void)prepareLayout {
self.itemSize = CGSizeMake((self.collectionView.frame.size.width/2), (self.collectionView.frame.size.height/2));
self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.minimumInteritemSpacing = 0;
self.minimumLineSpacing = 0;
}

Related

How to change UICollectionViewCell size programmatically (with Xib)

I created a custom subclass of UICollectionViewCell along with a Xib which defines a size for the cell (60 pts by 60 pts).
I also implemented the following:
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = [MainScreen screen];
CGFloat width = size.width;
CGFloat item = (width*60)/320;
return CGSizeMake(item, item);
}
The issue I'm running into is that every time I run my program, the cells in my UICollectionView controller always appear as 60x60 cells. Furthermore, I've been testing on an iPhone 6s which is 375x667 points (so, doing the math, the cells should be ~70x70 not 60x60).
How do I programmatically change the size of the cell (or, rather, override the predefined Xib size)?
This was just inexperience showing on my end. sizeForItemAtIndexPath: was working properly, however the actual frame of the cell image needed to be redefined based on the item parameters. So if I hard coded CGSizeMake(100,100) for the size of my collection view cell, I needed to also resize the image frame that would occupy the cell to 100x100.

UICollectionViewCell sized relative to its collection-view

I have a (horizontal) collection-view, and I change its size via auto layout constraints. However, when the collection-view's size changes, the cell remains the same static size.
To demonstrate, here's the collection-view in the view debugger (I've labeled both the collectionview and one of its cells):
As you can see, the cell remains the original size and is now actually taller than its encasing collection-view.
So how can I constrain the cell to always fit within its collection-view?
If you want to resize your view you can use the following to reset the item size on rotation, this would go inside your view controller subclass.
This should be fairly efficent as it is only called when the size of the visible view controller changes.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:({
^(id<UIViewControllerTransitionCoordinatorContext> context) {
UICollectionViewFlowLayout *layout = (id)self.collectionView.collectionViewLayout; {
CGFloat height = CGRectGetHeight(self.collectionView.bounds);
layout.itemSize = (CGSize) {
.width = height,
.height = height
};
}
[layout invalidateLayout];
};
}) completion:nil];
}
You should also check out these answers for some more solutions.
I solved this through setting the item's height and width equal to the collection-view's height. I do this in sizeForItemAtIndexPath:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(collectionView.frame.size.height, collectionView.frame.size.height);
}
Because in my case the cell's need to be perfect squares, setting the cell's height and width to the height of the collection-view works perfectly.
Not that your class must implement the UICollectionViewDelegateFlowLayout protocol for this method to be exposed.

iOS - UICollectionView still have spacing between cells after set to 0

Im getting small spaces between cells when setting everything to 0. All I did in the cellForItemAtIndexPath is setting backgroundColor for each cell.
Here's my code:
//collectionView frame
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150) collectionViewLayout:layout];
...
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
//The cell sizes are divided by the width of the collectionView.
return CGSizeMake(_collectionView.frame.size.width/12, _collectionView.frame.size.width/12);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0f;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 0.0f;
}
My collection view looks like this. You'll see that there are black lines between some cells. What is causing this? How can I remove the lines?
Any help is greatly appreciated. Thanks in advance.
I too faced this problem. Thanks to #tenric for pointing out and yes for me was because the width is not divisible by the number of desired columns. My solution as follow:
var itemWidth: CGFloat {
get {
return floor(view.frame.size.width / 7)
}
}
And because I'm using AutoLayout, I just adjust the gap to the width of the collectionView as follow (refer to widthAnchor):
collectionView?.topAnchor.constraint(equalTo: headerSeparator.bottomAnchor).isActive = true
collectionView?.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
collectionView?.bottomAnchor.constraint(equalTo: footerSeparator.topAnchor).isActive = true
let gap = view.frame.size.width - (itemWidth * 7)
collectionViewWidthConstraint = collectionView?.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -gap)
because both width and height are not divisible by 12,so it would remain some empty pixel point.To avoid this,both width and height of collectionView should be multiples of 12.
I was going crazy over this too. I wanted a generic solution since I had 3 cells per row for iPhones and 4 cells per row for iPads and the UICollectionView was covering the entire width of the screen and the width is different between all devices.
I ended up making the combined width of the cells on a row wider than the device screen by using ceil(frame.width / itemsPerRow). I then calculated the total width of the cells on a row and compared with the screen width (view.frame) to get the width overflow the cells would create. Knowing the overflow I set the trailing constraint of the UICollectionView to be negative the overflow. This means the UICollectionView is actually going to overflow the screen width with a pixel or so, but in my case this was not an issue. Hopefully the code below will help clarify and give you an idea of how this could be solved.
// calculating cell width
let frame = view.frame
let cellWidth = ceil(frame.width / itemsPerRow)
// adjust UICollectionView to avoid space between cells
let totalCellsWidth = cellWidth * itemsPerRow
let overflow = totalCellsWidth - frame.width
let adjustedConstraint = -overflow
collectionViewsTrailingConstraint.constant = adjustedConstraint

How to get Storyboard to support dynamically sized cells in UICollectionView?

I have the following layout in my dynamically-sized Storyboard:
However, when running the application (depending on the orientation), cells look like the following:
This is to be expected, because the previous cells had static heights and widths.
However, I'd like the cells to resize dynamically based on the device width (height can remain static for this purpose). The CollectionView itself resizes properly, because it's pinned to its superview, so how can cells be overridden with auto-layout constraints (vs. the static cell sizes dictated from the UICollectionView).
The simplest way seems to be over-riding the cell size via the delegate within my main View Controller:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
float cellWidth = (self.view.frame.size.width / 2) - 35;
float cellHeight = cellWidth * 190.0f / 270.0f;
return CGSizeMake(cellWidth, cellHeight);
}
I'd prefer to have as much display logic in the storyboard, but I suppose this is room for future improvement for Apple.
The cell sizes aren't determined by auto layout, they're set by the itemSize property of the layout object. If you only have one cell type, then you only need one cell in the collection view in IB. When your collection view is loaded, you can set that size in code, based on the width of the collection view. I've done it like this,
-(void)viewWillLayoutSubviews {
self.layout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/2.5, 100);
}

UITableView when changing orientation to landscape cell hight extreme high

I have a UIView with a NavigationController and a tableView. The table has 1 prototype cell and contains some labels. All "designed" with the storyboard and all constraints are set automatically. So I did with 10 UIViews (for iPhone) in my app, 9 of them displaying correct in portrait- and landscape-mode. One is ok for Portrait-mode, when turning to landscape there is a space about 300px between the cell witch has content for one line and the cell which has content for 20 or 30 lines. And the same space is at the end of that cell. I tried several other constraints, also manual done. I tried other x/y/width/height - settings for the labels without success. The code for the cell-height is:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (!self.cellNews) {
self.cellNews = [self.tableView dequeueReusableCellWithIdentifier:#"CellNews"];
}
theAktuellList = [app.aktuellArray objectAtIndex:indexPath.row];
NSString *currentLanguage =
[[NSString alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"/Documents/sprache.txt"]
encoding:NSUTF8StringEncoding error:NULL];
if ([currentLanguage isEqual:#"de"])
{
self.cellNews.Titel.text = theAktuellList.TitelD;
self.cellNews.Datum.text = theAktuellList.DatumD;
self.cellNews.Nachricht.text = theAktuellList.NachrichtD;
self.cellNews.Wichtig.text = theAktuellList.WichtigD;
}
else
{
if ([currentLanguage isEqual:#"fr"])
{
self.cellNews.Titel.text = theAktuellList.TitelF;
self.cellNews.Datum.text = theAktuellList.DatumF;
self.cellNews.Nachricht.text = theAktuellList.NachrichtF;
self.cellNews.Wichtig.text = theAktuellList.WichtigF;
}
else
{
self.cellNews.Titel.text = theAktuellList.TitelE;
self.cellNews.Datum.text = theAktuellList.DatumE;
self.cellNews.Nachricht.text = theAktuellList.NachrichtE;
self.cellNews.Wichtig.text = theAktuellList.WichtigE;
}
}
[self.cellNews layoutIfNeeded];
CGFloat height = [self.cellNews.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 40;
}
The app is a universal-app. This UIView with the tableView inside and the same content works without any issues on the Pad. Where is my fault or what can I change or try to solve that problem?
EDIT due to Answer of Raj:
Hi Raj, thanks for the link. I went through and found nothing. But I do it again tomorrow. Maybe I didn't talk about the cell and its labels. I have 1 prototype-cell with a height of 45. Inside I have 4 labels with each 25 hight and 10 top and 10 bottom constraint. "Title" has 20 left & right, "Date" has 30 left and 20 right, "Message" has 30 left and 20 right and "Wichtig" has 20 left and right. They are all placed one over the other, because in each cell only one label is used. That means the first cell contains only the Titel, the second cell the Date, the third cell the Message and so on. All constraints of each label are blue and as long as I have only one line of text in the label the cell is built correct. With every additional text line the "top- and bottom-padding" is growing. But the constraint is set to a fixed value.
EDIT 14.08.2014:
I went through the tutorials without any positiv changes. The labelheight is "calculated depending on the labelwidth in portrait orientation. When rotating to landscape, the label has exact the same height as in portrait orientation but the width has grown to nearly twice. The result is a less real textheight which is centered horizontal in the label.
I added a, I think it is more a dirty trick than a proper solution, a returning of height depending the label with long content is used:
CGFloat height = [self.cellNews.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
if ([self isLandscapeOrientation]) {
if (theAktuellList.NachrichtD == nil) {
return height + 1;
} else {
return height/1.5;
}
} else {
return height + 1;
}
This works "optically" fine, I get no hint or error but there must be better ways of solving that issue. Every help in which direction to learn/think or searching would be nice.
Please go through the below mentioned tutorial which explain Dynamic Table View Cell Height and Auto Layout using which you will get an intended output
http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout

Resources