UICollectionView Cell subview resizes after collectionView: cellForItemAtIndexPath is complete - ios

I am using a collection view to display a collection of profile images and the person's name. So my cell has a UIImageView and a UILabel as subviews. I am using the UICollectionViewDelegateFlowLayout method:
collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
to calculate the cell's size depending on the available space.
All of this is working fine. I have added constraints to my subviews in the cell so that they also resize accordingly.
The issue I am running into is that I want my UIImageViews to be circles. It seems like auto layout is not recalculating the cell's subview size until after I have applied that effect. Instead, when I calculate the cornerRadius for the imageView it is still saying the imageViews width is 114.0 (which is what is in the storyboard) regardless of how big the cell is. This results in circles on the iPhone 5s but only rounded corners on any bigger device. Here is my code for that:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("PersonCell", forIndexPath: indexPath)
configureCell(cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: UICollectionViewCell, atIndexPath indexPath: NSIndexPath) {
if let person = personAtIndexPath(indexPath) {
let imageView = cell.viewWithTag(100) as! UIImageView
let nameLabel = cell.viewWithTag(200) as! UILabel
cell.contentView.frame = cell.bounds
cell.contentView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
circularizeImageView(imageView)
imageView.image = person.profileImage
nameLabel.text = person.name
}
}
func circularizeImageView(imageView: UIImageView) {
imageView.layer.cornerRadius = (CGRectGetWidth(imageView.bounds) / 2)
imageView.clipsToBounds = true
imageView.layer.borderWidth = 2.0
imageView.layer.borderColor = UIColor.whiteColor().CGColor
}
I saw in a couple places that previously the subviews would not resize at all like here: UICollectionView cell subviews do not resize
I don't think this is an issue any more, however I did add the fixes into my code as you can see in configureCell() but it still isn't helping.
So it seems like those subviews are not resized until after the cellForItemAtIndexPath call is completed. Any thoughts on how I might address this? See screenshot of :rounded corners on UIImageViews instead of complete circles

Don't use viewWithTag(), it's bad practice. Instead make the UILabel and UIImageView public or leave off the scope modifier.
Is the UIImageView a fixed size? If so, you don't need to call circularizeImageView() each time a cell is reused. Instead, call it in layoutSubviews() in your UITableViewCell subclass. This will also give you the correct size for imageView.bounds.height

Related

Constrains for ImageView is not working

I have used AutoLayout with one of my UICollectionView I'm facing issue with height and width for imageView. I have added UIImageView in my UICollectionViewCell like following with below constraints.
UICollectionViewDataSource methods.
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
var width = Int((collectionView.frame.size.width - 30) / 4)
if width % 2 != 0 {
width += 1
}
return CGSize(width: CGFloat(width), height: CGFloat(width))
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
print("Cell Size - \(cell.bounds)")
print("ImageView Size - \(cell.imageView.frame)")
return cell
}
But when I run this the ImageView is always coming with 70X70 no matter on which device I will run but UICollectionViewCell size is increasing and decreasing on different devices.
On iPhone 6 it will looks like below.
I have set backgroundColor of UIImageView to white color and red color for UICollectionViewCell so that it will give batter understanding the console log for Cell and ImageView Size is as below.
Cell Size - (0.0, 0.0, 86.0, 86.0)
ImageView Size - (5.0, 5.0, 70.0, 70.0)
Cell Size - (0.0, 0.0, 86.0, 86.0)
ImageView Size - (5.0, 5.0, 70.0, 70.0)
Please any one help me why the imageView size is not increasing or decreasing according to the UICollectionViewCell. Any help would be appreciated.
in size inspector of collection view ,set Estimate Size to None
After researching a bit I have came up with the following way to solved this issue of AutoLayout with UICollectionViewCell. From Xcode 6 CollectionViewCell doesn't show the contentView in interface builder, so in the awakeFromNib of cell I have set its autoresizingMask and it works like charm.
class CustomCell: UICollectionViewCell {
#IBOutlet
var imageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
//Below line solved my problem
self.contentView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
}
}
you need to set constraints as below screenshot;
Center horizontally and Center vertically Constraints should not be there when pin to parent all the sides(Top,Bottom,Leading & Trailing) were given for your Image view.
Either remove Center horizontally and Center vertically Constraints
Or Top,Bottom,Leading & Trailing and give equal widths and heights as parent along with centre vertically and horizontally.
Seems removing Center horizontally and Center vertically Constraints will solve your problem for sure,give it a try.
Hope that helps.
Good luck.

Change UICollectionViewCell height to fit UILabel

I am trying to make my cell height size fit with label. The thing is that the label text is set in the cellForItemAtIndexPath, and if i have understood correct, sizeForItemAtIndexPath runs before the cellForItemAtIndexPath. This is something i have tried so far:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let imageCell = collectionView.dequeueReusableCellWithReuseIdentifier("imageCell", forIndexPath: indexPath) as? CollectionViewCell
imageCell!.imageText.text = post.text // This set the UICollectionView Cell text
imageCell!.frame.size.height = (imageCell!.frame.size.height) + (imageCell!.imageText.frame.size.height)
return imageCell!
}
I am not using Auto Layout.
Any suggestions why the cell height not changes depending on the label?
This used to be an annoying problem to solve, but it gets substantially easier if you're able to use Auto Layout. See this answer for a thorough walkthrough.
Even if sizeForItemAtIndexPath runs first, that's the place to set the size of the cell. cellForItemAtIndexPath cannot change the size.
In sizeForItemAtIndexPath you need to find out the image size for each cell, then return that size.
Something like this:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let imageCell = collectionView.cellForItemAtIndexPath(indexPath) as! CollectionViewCell
let size = CGSize(width: imageCell.frame.width, height: imageCell.frame.size.height + imageCell.imageText.frame.size.height)
return size
}

How to add a background image to a UICollectionViewCell in Swift?

I had assumed that it would be easy to add a background image to a UICollectionViewCell, but I am having trouble figuring it out. I have a border image like this that I want to add to every cell in my UICollectionView.
border.png
I couldn't see an option to add it in the Interface Builder and I'm not sure which method to use on UICollectionViewCell programmatically.
I have seen these similar questions:
UICollectionView Cell with Image, change Background with click (image is already added)
How to add a background image to UICollectionView that will scroll and zoom will cells (UICollectionView, not UICollectionViewCell)
I know this is a old question, with an accepted answer. But why not just set the border of the cell like so:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
cell.layer.borderWidth = 1.5
cell.layer.borderColor = UIColor.blueColor().CGColor
cell.layer.cornerRadius = 4
return cell
}
That way you don't need to use a image. Just adjust the borderWidth and cornerRadius until you get the desired effect.
let View=UIView()
View.backgroundColor=UIColor(patternImage:UIImage(named:"border.png")!)
cell.backgroundView=View
in uicollectionview cellForItemAtIndexPath method
Add a UIImageView to your CollectionViewCell and set this image as the image.

UIImageView created in UICollectionView remains black

My imageViews still doesn't display an image, would be very grateful if someone could point to what is going wrong.
Here's the collection view function:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("CELL ID", forIndexPath: indexPath) as! UICollectionViewCell
let imageView = UIImageView(frame: cell.contentView.bounds)
imageView.image = UIImage(named: "gear.png")
cell.contentView.addSubview(imageView)
return cell
}
And in viewDidLoad I have:
collectionView.delegate = self
collectionView.dataSource = self
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "CELL ID")
The cell is identified with the correct CELL ID and I know that part is working because I can set the background color of these cells and it'll show up. The imageView shows up black. I can set the background color at the same time I set the imageView and the color will show.
Make sure that you have image Named gear and also check the extension.

SelectedBackgroundView of UICollectionViewCell visible when it should not be

I've got a UICollectionView. With some cells inside with a white background color. I've set the selectedBackgroundView to a basic purple view.
My CollectionView has a constraint with a height of 0 and when I hit a button I update the constraint to 80. When I'm doing that, during the animation i can see the purple background on the screen until the end on the animation and i cannot understand why or how prevent this ?
Everything else working fine, it's just a "visual" bug.
Any suggestion about how to fix this ?
Gif of the bug where you can see the purple appearing during the animation
Here is my cell construction if it can be of any help :
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("WidgetMenuCellIdentifier", forIndexPath: indexPath) as UICollectionViewCell
cell.removeSubviews()
// some code setup
cell.selectedBackgroundView = UIView()
cell.selectedBackgroundView.backgroundColor = UIColor.purpleColor()
return cell
}
Subclass your UICollectionViewCell
Do
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
// your code
cell.selectedBackgroundView.hidden = true
return cell
}
Then in your subclass :
override var selected:Bool {
willSet {
self.selectedBackgroundView.hidden = false
}
}
It should work.
It seems like this code is being executed within an animation, causing unexpected behavior at times based on how various properties animate. Another complicating factor is that, because cells are reused, it won't reproduce if a reused cell is already configured correctly (i.e. there is nothing to animate). Adding the following after styling the selectedBackgroundView was the least hacky solution I could think of.
[cell.selectedBackgroundView.layer removeAllAnimations];
Depending on what your cells are like you may also want to consider removing animations on other layers as well. For example:
[cell.backgroundView.layer removeAllAnimations];

Resources