I'm facing a problem where I want to realize a UICollectionView that essentially builds up from the center.
Let's say I have this view which shows a list of people:
When the user keeps adding multiple persons using the +, I want the CollectionView to expand but stay in the center of the view:
How do I realize this behavior?
If you are not using autolayout and size classes then you can set "center" is a collection view like this...
[collectionView setCenter:self.view.center];
And if autolayout is enabled and you are using it then do this...
Set CenterX and CenterY constrains of collection view
Set Height and width constraints of collection view
Instead of a custom flow layout, an alternative approach would be to have a full height collection view as normal and then set a top and bottom inset to visually center the cells:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
let inset = (collectionView.frame.size.height - ((COUNT_OF_CELLS / CELLS_PER_ROW) * HEIGHT_OF_CELL) / 2)
return UIEdgeInsetsMake(inset, 0, inset, 0);
}
You will need to keep track of the total number of cells, number of cells on a row, and the cells height for the calculation to work right.
Related
TableView Description
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
Cell Description
I have a cell with 2 Labels(Title, Description) inside a ContainerView and 1 ImageView as below. Cell height will vary based on Description Label’s content.
Contraints of all views
There are two cases that I should handle
ContainerView.height greater than (ImageView.height + ImageView.Top + ImageView.Bottom). Here cell's height will be based on ContainerView.height
ContainerView height less than (ImageView.height + ImageView.Top + ImageView.Bottom). Here I expect Cell should consider (ImageView.height + ImageView.Top + ImageView.Bottom) as the height and make ContainerView vertically centre to Cell.
Expected Result in both the cases
Problem
If I set constraints for 1st case then 2nd case is not working and vice versa (I’m aware that by removing ContrainerView.Top, Bottom and making it Vertically Centre to SuperView case 2 result can be achieved)
Is there a way to achieve expected result in both the cases by using same set of IB constraints and UITableViewAutomaticDimension?
Give fixed height and width to the image view . Otherwise let the tableViewCell know the top and bottom of the imageview. So that it can calculate the correct cell height
First make sure that you are using self-sizing cells:
https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html
Make Top and Bottom constraints for both image view and the container view to the edges of the cell and make them >=.
Alternatively, you could try Horizontal Stack View and make rigid (highest priorities) constraints to each edge of the cell.
Use these delegates,
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100; // height of default cell
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
Edit
Try this one.
Your view hierarchy should be like this
ImageView Constraints
Add a view and put both labels into it.
Label Container contraints
Label Title constraint
Label Description constraint
Edit Output
I'm trying to change minimumLineSpacing for some cells depending on what row they are.
Imagine having 10 cells; I want minimumLineSpacing to be 8 for all of them except for cell number 7.
I tried doing it via delegate:
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
But I just wish that it would pass back a NSIndexPath instead of a section.
I'd appreciate any input.
One workaround:
If you have it subclassed , you should be able to do this very easy with autolayout and a XIB.
Example:
If you have a constraint in the cell to the bottom of the contentView, you can simply set the constraint to an NSLayoutConstraint property and update the constant of the constraint for that specific cell only to give an extra spacing.
To keep the same proportions and height as the rest of the cells, you only add the extra spacing (same as you added to the constant) to the itemSize.height to that specific cell.
If you don't have this subclassed with autolayout or anything. You can do it programatically the same way but with a subView frame CGRect
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);
}
UICollection has paging just like a UIPageViewController. With the latter, you have UIPageViewControllerOptionInterPageSpacingKey to easily set the spacing. How is this best achieved with a UICollectionView?
You can probably accomplish explicitly with UICollectionViewLayoutAttributes, but my approach (that works for collection views and my own subview-containing scroll views) is to tile the cells with no spacing (which makes the layout math simple), but make the cells transparent.
Then within each cell create a more opaque content view whose frame is an insetRect on the cell's bounds.
You can use the collectionView:layout:insetForSectionAtIndex: method for your UICollectionView. You need to add this code...
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{
return UIEdgeInsetsMake(top, left, bottom, right);
}
it was answered here: UICollectionView spacing margins by #michael23
I have a grouped tableView in my iPad-app, and I've been trying to set cell.imageView.center = cell.center to center the image instead of putting it to the leftmost position. This is apparently not possible without a subclass of the UITableviewCell(If someone could explain why, that'd also be appreciated.. For now I just assume they are 'private' variables as a Java-developer would call them).
So, I created a custom tableViewCell, but I only want to use this cell in ONE of the rows in this tableView. So in cellForRowAtIndexPath I basically write
cell = [[UITableViewCell alloc]initWith//blahblah
if(indexPath.row == 0)
cell = [[CustomCell alloc]initWith//blahblah
This is of course not exactly what I'm writing, but that's the idea of it.
Now, when I do this, it works, but the first cell in this GROUPED tableView turns out wider than the rest of them without me doing anything in the custom cell. The customCell class hasn't been altered yet. It still has rounded corners though, so it seems it knows it's a grouped tableView.
Also, I've been struggling with programmatically getting the size of a cell, in cellForRowAtIndexPath, I've tried logging out cell.frame.size.width and cell.contentView.frame.size.width, both of them returning 320, when I know they are a lot wider.. Like, all the rows are about 400 wide, and the first cell is 420 or something. It still writes out 320 for all the cells..
This code will not work for a couple of reasons:
cell.imageView.center = cell.center;
Firstly, the center is relative to its superview. I believe the cells superview is the tableView. The imageView's superview will be the content view of the cell. Therefore the coordinate systems are different so the centens will be offset. E.g. the 3rd cell down will have a center of 0.5 widths + 3.5 heights. You should be able to ge around this issue by doing:
cell.imageView.center = CGPointMake( width / 2 , height / 2 );
The second issue is related to how the table view works. The table view manages its cells view's. The width of a cell is defined by the table view's width and the height is defined by the table view's row height property. This means the cell itself has no control over its size.
You can however size its subviews, but you must do this after the cells size has been set (otherwise you can get strange results). You can do this in layout subviews (of the custom UITableViewCell class). See this answer.
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = ....
}
When layoutSubviews is called the cells frame has been set, so do your view logging here instead of cellForRowAtIndexpath.
As for the GROUPED style. Im not sure if this is designed to work with custom views. I suspect it sets the size of its cells to its own width minus a 20 pixel margin on each size, then applies a mask to the top and bottom cells in a section to get the rounded effect. If you are using custom view try to stick with a standard table view style.