I have a UICollectionView which basically appears like a table, it has a horizontal stack of UICollectionViewCell views. I want the standard UIViewController layout margins (16pt on the left and right on an iPhone X) to apply to the contents of the cells. This happens in a UITableView.
For some reason my cells initialise with the out of the box margins (8pts) and never update.
I have checked all these options in my cell's .xib, and can log out the layoutMargins property to reveal that the value is correct, but the subviews just never move.
Any ideas?
It turns out that, although you can't see it in Interface Builder, a UICollectionViewCell has a content view, which does not by default inherit layout margins.
This solved it for me:
- (void)awakeFromNib
{
[super awakeFromNib];
self.contentView.preservesSuperviewLayoutMargins = YES;
...
}
Be careful on devices/views with safe area insets set, this may knock around the bottom insets of your cell.
Related
I need pretty simple thing - table cells which automatically detect their own height. There are a lot of examples out there, which basically say "set couple of flags and values on your table and use autolayout in your cell". My case is a bit special - I load the content of the cell from a separate XIB file which is a plain UIView. The first problem comes already when I create that XIB file in interface builder - I don't know how to make it's height to "calculate" according to constraints that I specify. I am always getting IB errors unless I switch to "Freeform" and resize the view to the height matching my constraints. If I don't do that, I will get the following errors:
In the above example I just need a view which height will be 32 (image height) + 2 * 16 (vertical distance constraints of image from parent's top and bottom) plus the margins. Resizing the freeform view in IB until the errors disappear seems like a dirty hack to me, and it is actually not autolayout. As a next step, I define a cell class, where I put this xib view, something like this (sorry for objc code, almost done porting the project to swift):
- (void)awakeFromNib {
[super awakeFromNib];
[[NSBundle mainBundle] loadNibNamed:#"CellContent" owner:self options:nil];
// self.content is an outlet which gets the root of the XIB on load
[self.contentView addSubview:self.content];
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView.leftAnchor constraintEqualToAnchor:self.content.leftAnchor].active = YES;
[self.contentView.rightAnchor constraintEqualToAnchor:self.content.rightAnchor].active = YES;
[self.contentView.topAnchor constraintEqualToAnchor:self.content.topAnchor].active = YES;
[self.contentView.bottomAnchor constraintEqualToAnchor:self.content.bottomAnchor].active = YES;
}
As you might guess, when I run this the cell height is the big freeform one, like in the IB of the content XIB, so no auto layout. It seems like the freeform height is even added as another constraint and there is a constraint conflict which results in some of them being broken at runtime.
Let me know how can I fix this, easily create content views for my cells which have auto heights and which I can embed in my cells to benefit the tableView.rowHeight = UITableViewAutomaticDimension magic?
Maybe you forgot to set the Content Hugging Priority and Content Compression Resistence Priority of the Labels.enter image description here
I found what was my problem. Actually, there were conflicts with constraints added because of autoresizing. So I changed this line (from the question above):
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
to:
self.content.translatesAutoresizingMaskIntoConstraints = NO;
Stupid mistake, the translatesAutoresizingMaskIntoConstraints flag should be disabled for the child view after adding, not for the parent view, as I incorrectly did. After that the magic with cell auto height detection started working like charm.
Make sure UILabel has multiline property . So , Set 0 for Line Property at Attribute Inspector .
Make sure that UILabel Auto-Layout is properly relative to Left-Right-Top-Bottom .
Apply these delegate Functions :
-(CGFloat) tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
I'm animating the height of a UITableView so it aligns with the keyboard's animation like in this article: //http://macoscope.com/blog/working-with-keyboard-on-ios/
However, I am now getting unwanted sideways animations in my cells as they come in.
This used to work when I was adding the contents to the cell view directly because I would override the UITableViewCell method:
- (void)layoutSubviews
{
[UIView performWithoutAnimation:^{
[super layoutSubviews];
}];
}
But now I'm adding the contents to contentView like you're supposed to. I need to so the ios8 auto resizing works. But the solution of laying out subviews without animation no longer seems to apply to content view.
(I just tried not adding things to contentView and the auto sizing still works actually. I'm still interested in knowing how to properly get contentView contents to not have unwanted animations)
Xcode Interface Builder is driving me nuts and I've spent most of my day googling for a solution.
I have a storyboard with a CollectionViewCell that contains a UIImageView. The CollectionViewCell size is 125 x 125 and Autoresize subviews is checked.
The UIImageView has 4 constraints to its superview (leading, trailing, top, bottom), all set to 0. This should ensure that the UIImageView is sized to fill the superview. The UIImageView is sized correctly when the CollectionViewCell is shrunk to a smaller size, but IT DOES NOT WORK when the CollectionViewCell is stretched to a larger size.
EDIT: I've tried the same using a UILabel subview and the same thing happens.
Is this a known problem or is there any way to debug constraints?
Thanks
I've finally found a complete solution to the problem from http://www.nomtek.com/adjusting-your-app-to-ios-8/
Firstly, I had to ensure my CollectionViewCell had Autoresize Subviews checked in Interface Builder, then I had to add the following awakeFromNib method on the ConnectionViewCell subclass.
- (void)awakeFromNib {
[super awakeFromNib];
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
With these two things, the contents of my cells (UIImageView and UILabel) are stretched properly even with dynamic cell sizing using sizeForItemAtIndexPath.
I've made partial progress.
I was setting the cell size dynamically using sizeForItemAtIndexPath.
If I drop that method and set a larger Cell Size of the CollectionView's FlowLayout in Interface Builder, it works as expected. This means the constraints and subview size are updated at compile time.
I would still love to know how to dynamically update the constraints and subview sizes when using sizeForItemAtIndexPath. Any suggestions?
I have a UICollectionViewCell subclass that I have defined in a nib...
It uses AutoLayout to layout all of the (two, lol) components. The date picker is laid out with left, right and bottom constraints to the superview and a height constraint to make sure it always shows full content.
Then, when configuring the layout of the collection view I use this...
_layout = [[UICollectionViewFlowLayout alloc] init];
_layout.itemSize = CGSizeMake(CGRectGetWidth(self.collectionView.frame), CGRectGetHeight(self.collectionView.frame));
_layout.minimumInteritemSpacing = 0;
_layout.minimumLineSpacing = 0;
This works as when I'm debugging the view I can see that the frame of the UICollectionViewCell is correct, but the content of the cell is not resizing as you can see from these two screenshots.
Collection View Cell selected and is correct.
Content of collection view selected and is not correct.
In fact, you can see that the content is the same size and shape as defined in the nib. But
this should resize to match the cell size. If I make the nib content really small it stays really small in the app.
This is, potentially, happening in UITableViewCells too as the cell separators are not showing all the way across the screen for bigger devices.
I cannot resize the uitableview properly when changing the orientation of the screen. I can make one orientation work fine but not both.
I've tried 2 different methods: 1) using the autoresizingMask on the tableview and 2) using the layoutSubviews method and here are the results of each:
1) using the autoresizing almost works if I use
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin;
It shows correctly when in portrait and then I move to landscape it also shows correctly but not all the way to the end of the screen. In landscape I see a space on the left side and on the right side.
So, I thought let's just add the UIViewAutoresizingFlexibleWidth to the line of code above. It does make the uitableviewcell expand to the full screen in landscape but when I change the orientation it does not maintain the same cell on the screen and sometimes it displays half of one cell and half of another cell in the middle of the screen.
2) Using auto layout. I get the same behavior as above when I use this code:
-(void)layoutSubviews {
[super layoutSubviews];
onLoadSize=self.contentView.bounds.size;
self.myTableView.frame = CGRectMake(0, 0, onLoadSize.width, onLoadSize.height);
self.selectedBackgroundView.frame = self.myTableView.frame;
}
If I add an if statement testing for the orientation, then it works fine for that orientation in specific but not the other. If I test for both orientations I get the same behavior as described above.
Any help will be very welcome.
Thanks!
UITableViews usually occupy the full space of the parent view controller and typically don't need constraints or active resizing, unless you have more than one table view in a single view.
Consider managing the content of UITableViewCells (instead of managing the table view) by:
(1) Applying constraints to each custom cell in Interface Builder.
(2) Redrawing the cell's frame to fit the parent UItableView when the cell renders its subviews (layoutSubviews method).
(3) Calling [cell.contentView needsUpdateConstraints] to force the cell contents to redraw.
Here is some sample code for cell's custom class:
-(void)layoutSubviews
{
resizeCell:self forView:[the cell's UITableViewController.view]
}
Here is a generic function you can add anywhere for reuse:
-(void)resizeCell:(UITableViewCell *)cell forView:(UIView *)view
{
cell.contentView.frame=CGRectMake(cell.contentView.frame.origin.x,
cell.contentView.frame.origin.y,
view.frame.size.width,
view.frame.size.width,
cell.contentView.frame.size.height);
}
Please note the cell's UITableViewController must be passed to the cell's custom class (as a member variable) for the code above to work.
Good luck!