UICollectionViewCell outlet frame change animation - ios

I have a UICollectionView which uses a waterfall style layout to show different sized cells. The height calculation for each cell works just fine.
The problem I have is that I have to change the size of two outlets (UIImage and UILabel) in each cell and I donĀ“t know where to change the frame size in order prevent the UICollectionView from animating said frame size change. I tried it to do in the layoutSubviews method of each cell and in the cellForItemAtIndexPath without results. Every time the viewcontroller containing the UICollectionView appears the frame change for the two outlets in each cell is animated.
Example setting the frame for just the image inside cellForItemAtIndexPath:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CVCNewspaper *cell = (CVCNewspaper *)[collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER_NEWSPAPER forIndexPath:indexPath];
BONewspaper *newspaper = [newspapers objectAtIndex:indexPath.row];
CGFloat width = cell.frame.size.width;
// Calculate rect for imageView
CGFloat objectWidth = newspaper.coverNews.imageWidth ? newspaper.coverNews.imageWidth : 180;
CGFloat objectHeight = newspaper.coverNews.imageHeight ? newspaper.coverNews.imageHeight : 100;
CGFloat scaledHeight = floorf(objectHeight / (objectWidth / width));
cell.imageViewCover.frame = CGRectMake(MARGINVIEW, HEADERHEIGHT + 5, width, scaledHeight);
[cell fillCellWithNewspaper:newspaper];
return cell;
}

Related

Display CollectionViewCell in starting position

I created a collection view cell with the Xib file. And I have only one cell, but that cell displaying in the center of the collectionView. I want to display cell at starting position of the collectionView.
I fixed contentInset in viewDidLoad and loading cell xib file here,
_listCollectionView.contentInset = UIEdgeInsetsMake(0 , 0, 0, 0);
And my cell size is
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return CGSizeMake(156,140);
}
Cell displaying like this.
Im not very clear with your question but i think what you are referring to is to align the collectionnView element to the view . You have to use UICollectionViewLayoutAttributes or layoutAttributesforElements to achieve this . Take look at the below code and to make if you want it in Objective c.
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
CGFloat leftMargin = self.sectionInset.left; //initalized to silence compiler, and actaully safer, but not planning to use.
CGFloat maxY = -1.0f;
//this loop assumes attributes are in IndexPath order
for (UICollectionViewLayoutAttributes *attribute in attributes) {
if (attribute.frame.origin.y >= maxY) {
leftMargin = self.sectionInset.left;
}
attribute.frame = CGRectMake(leftMargin, attribute.frame.origin.y,
attribute.frame.size.width, attribute.frame.size.height);
leftMargin += attribute.frame.size.width + self.minimumInteritemSpacing;
maxY = MAX(CGRectGetMaxY(attribute.frame), maxY);
}
return attributes;
}
In collectionView: cellForItemAtIndexPath: function i made changes like this.
Here just i fixed my collectionviewcell x origin position to 0 after loading the cell.
deviceCell= (DeviceCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"DeviceCollectionViewCell" forIndexPath:indexPath];
if (listArray.count == 1) {//Here i fixed the my cell x origin position
CGRect frameRect = deviceCell.frame;//Copy cell frame
frameRect.origin.x = 0;//Set cell origin.x
deviceCell.frame = frameRect;//Reset frame
}

Force UICollectionViewCell resizing after resizing UICollectionView

In my uicollectionview delegate, i have this code. Basically it is to set the size of the cells based on the colectionview size.
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGFloat ratio = 200.0/280.0; // w/h
CGFloat cellWidth = (collectionView.frame.size.width-50)/4.0;
CGFloat cellHeight = cellWidth / ratio;
CGSize cellSize = CGSizeMake(cellWidth, cellHeight);
return cellSize;
}
How can I force this delegate to run after I change the collectionView frame without reloading the collectionView? One way I think of is manually calling this funtion by looping through all visible cells, but seems way too heavy for something so simple.
HELLLPPPPPP
You can call this delegate manually like this :
CGSize size = [self collectionView:self.collectionView
layout:self
sizeForItemAtIndexPath:indexPath];
Ok I found the solution by myself. In order to force this delegate to run again after resizing collectionview, we just need to reload a SINGLE cell. For example, the first cell. Then collectionview will resize all cells automatically.
NSIndexPath *firstItem = [NSIndexPath indexPathForRow:0 inSection:0];
[_cardCollectionView performBatchUpdates:^{
[_cardCollectionView reloadItemsAtIndexPaths:#[firstItem]];
} completion:^(BOOL finished) {}];
Anyway thanks all for trying to help me.

The behavior of the UICollectionViewFlowLayout is not defined

I've got a collection view that's set up as a single horizontal row of cells. It's throwing the following constraint error (I'm using AutoLayout):
The behavior of the UICollectionViewFlowLayout is not defined because the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
I've Googled around and looked on SO, and everyone suggests that it's fixed by simply overriding the UIScrollViewDelegate methods:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
// iPhone 6+ device width handler
CGFloat multiplier = (screenWidth > kNumberOfCellsWidthThreshold) ? 4 : 3;
CGFloat size = screenWidth / multiplier;
return CGSizeMake(size, size);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(0, 0, 0, 0);
}
But it's still not working. It appears to be gawking at the fact that the cell height is taller than it's container, even though I'm setting the cell to the same hight as the container. Here's the rest of the error:
The relevant UICollectionViewFlowLayout instance is UICollectionViewFlowLayout: 0x7fa6943e7760, and it is attached to MyCollectionView: 0x7fa69581f200; baseClass = UICollectionView;
frame = (0 0; 375 98); clipsToBounds = YES; autoresize = RM+BM;
layer = CALayer: 0x7fa694315a60; contentOffset: {0, 0}; contentSize: {0, 134}
Setting the cell manually to a drastically smaller size (e.g. size - 50.0 seems to work, but why can't I set the cell size to the same height as its container?
Turns out the missing piece from my question was the fact that this UICollectionView is nested inside a UITableView. iOS 8 introduced layoutMargins in place of content offset values.
Per this question: iOS 8 UITableView separator inset 0 not working
I had to override my containing table view's cell margins:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove seperator inset
if ([cell respondsToSelector:#selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:#selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
// Explictly set your cell's layout margins
if ([cell respondsToSelector:#selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
swift for override cell
override func awakeFromNib() {
super.awakeFromNib()
self.separatorInset = .zero
self.preservesSuperviewLayoutMargins = false
self.layoutMargins = .zero
}

UICollectionView autosizing cells break UICollectionViewFlowLayout settings

I'm currently working on autosizing cells which are new in iOS8.
According to WWDC 2014 video 'What's New in Table and Collection Views', all that is required to autosize cells is to set an estimatedSize on the UICollectionViewFlowLayout given to the UICollectionView on initialisation, and override the sizeThatFits: method in the UICollectionViewCell.
Initialisation:
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setEstimatedItemSize:CGSizeMake(146.0f, 156.0f)];
_collectionView = [[UICollectionView alloc] initWithFrame:[_containerView bounds] collectionViewLayout:flowLayout];
sizeThatFits method in my cell, where _userLabel is the label that is on the bottom and marks the actual height.
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize actualSize = CGSizeMake([[self contentView] bounds].size.width, [_userLabel frame].origin.x + [_userLabel bounds].size.height);
return actualSize;
}
It turns out that actual size has larger height than my estimated size, which should be okay and the cell actually gets resized properly in height.
Now with the iPhone6 and 6+, the width can also differ. I want the cells to properly span the width of the screen. I've therefore implemented three delegate methods on UICollectionViewFlowLayout; my first intuition is to calculate the width I want the cells to have according to the screen width, the section insets and the inter-item spacing.
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
UIEdgeInsets sectionInsets = [self collectionView:collectionView layout:collectionViewLayout insetForSectionAtIndex:[indexPath section]];
CGFloat interItemSpacing = [(UICollectionViewFlowLayout *) collectionViewLayout minimumInteritemSpacing];
CGFloat cellWidth = ([_collectionView bounds].size.width - sectionInsets.left - sectionInsets.right - interItemSpacing) / 2;
CGSize collectionViewCellSize = CGSizeMake(cellWidth, 156.0f);
return collectionViewCellSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 12.0f;
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f);
}
It works, however partly. The collectionView won't respect the top section inset, and when scrolling the collectionView, switching out another tab and then back again, cells seem to have disappeared.
Apparently I'm doing something wrong, but I can't seem to figure out where. Anyone got a clue?

How to change UIImageView frame on UICollectionView cell when the UICollectionView loads?

MY OBJECTIVE: I need to load an image on the UICollectionView, but changing the Y position of it on the UIImageView frame, because the loaded image is taller than the cell display window, and I need to display a specific part of it.
SETTINGS: The UICollectionView and the UIImageView were manually added to the storyboard (not programmatically). The UIImageView view mode is set to Aspect Fill on the Attributes Inspector.
THE PROBLEM: I've tried changing the UIImageView frame after (and also before) loading the image, but the change only takes effect after the UICollectionView is scrolled up and down, and I need the image position updated when it first loads.
PS: I've also tried all the different types of view mode on the UIImageView, but it doesn't seem to make any difference.
Here's the coding I'm using for it:
- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCell *cell = (PhotoCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"PhotoCell" forIndexPath:indexPath];
cell.photoImageView.image = [UIImage imageNamed:_stringImageURL];
CGRect oldFrame = cell.photoImageView.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, -45, oldFrame.size.width, oldFrame.size.height);
cell.photoImageView.frame = newFrame;
cell.backgroundColor = [UIColor redColor];
return cell;
}
Any help would be greatly appreciated! Thanks in advance!

Resources