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.
Related
I have an app with a screen that is divided into four equal cells. Each cell has an image, label, and color. I'm trying to add the images in, but for some reason, only the image in the first cell works.
It looks like this now:
Here is my code:
In ViewController.swift:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
colorArray += [UIColor.red, UIColor.blue, UIColor.green, UIColor.yellow]
pictureArray += [UIImage(named: "budget")!, UIImage(named: "journey")!,
UIImage(named: "learn")!, UIImage(named: "settings")!]
titleArray += ["Budget", "Journey", "Learn", "Settings"]
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
// Set cell properties
cell.backgroundColor = colorArray[indexPath.row]
let imageview:UIImageView=UIImageView(image: pictureArray[indexPath.row])
let size = CGSize(width: 100, height: 100)
imageview.center = cell.center
imageview.bounds = CGRect(origin: cell.bounds.origin, size: size)
cell.contentView.addSubview(imageview)
let label = cell.viewWithTag(1) as! UILabel
label.text = titleArray[indexPath.row]
return cell
}
The labels and colors work fine, but for some reason, the image views seem to be off the screen. I have a feeling that my center/bounds restrictions are forcing the images off the screen, but I've tried many combinations, and none of them seem to work for me.
How should I do this?
I'm posting the correct answer for who ever will google here. (And because it was solved an hour ago without anyone posting the answer)
The best practice is to subclass UICollectionViewCell, connect all the outlets (label, image etc.) and work with this class on the cells
Good luck to all
This is what worked, after Yogesh Suthar's comment:
I subclassed UICollectionViewCell, connected the image and label:
class NavigationCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var navImage: UIImageView!
#IBOutlet weak var navLabel: UILabel!
}
Then, in the ViewController, I did this:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! NavigationCollectionViewCell
// Set cell properties
cell.backgroundColor = colorArray[indexPath.row]
cell.navImage.image = imageArray[indexPath.row]
cell.navLabel.text = titleArray[indexPath.row]
return cell
}
Set the size and position of the image and label in Main.storyboard!
insert the desired view as a subclass and setup all constrains to cell.heightAchor and so on. this will fix the bug for some reason. It works if the subview is added to the cell as a subview but not as an attribute of the cell
I have an issue where the data presented in a UICollectionView overwrites the label and the cell view is not getting cleared.
This image shows the issue,
IE:
My UICollectionViewCell which is constructed like so;
// in viewDidLoad
self.playerHUDCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier:reuseIdentifer)
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifer, for: indexPath) as UICollectionViewCell
let arr = UINib(nibName: "EYPlayerHUDView", bundle: nil).instantiate(withOwner: nil, options: nil)
let view = arr[0] as! EYPlayerHUDView
cell.contentView.addSubview(view)
if let allPlayers = self.allPlayers
{
let player:EYPlayer = allPlayers[indexPath.row]
view.updatePlayerHUD(player: player)
}
cell.layoutIfNeeded()
return cell
}
I use a view to display in the cell.
I tried removing all the cell's subchildren in the cellForItemAt but it appears to remove all the subviews.
I would like to know how do I clear the UICollectionViewCell so labels and other info on the UICollectionViewCell is not dirty like the example above.
Many thanks
Use prepareForReuse method in your custom cell class, something like this:
override func prepareForReuse() {
super.prepareForReuse()
//hide or reset anything you want hereafter, for example
label.isHidden = true
}
in your cellForItemAtIndexPath, instantiate your custom cell:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCellIdentifier", for: indexPath) as! CustomViewCell
Then, always in cellForItemAtIndexPath, setup your items visibility/values
//cell = UICollectionViewCell
for subview in cell.contentView.subviews {
// you can place "if" condition to remove image view, labels, etc.
//it will remove subviews of cell's content view
subview.removeFromSuperview()
}
UICollectionViewCells are reused to avoid instantiations, to optimize the performance. If you are scrolling and a cell becomes invisible, the same object is used again (dequeueReusableCell) and a new content is set in cellForItemAt...
As mentioned in the previous answers, before reusing the cell, prepareForReuse() is called on the cell. So you can overrride prepareForReuse() and do whatever preparation you need to do.
You are however creating and adding a new EYPlayerHUDView to the cell on every reuse, so your cell becomes full of stacked EYPlayerHUDViews.
To avoid this, subclass UICollectionViewCell and make the EYPlayerHUDView a property of your custom cell (I recommend to use a XIB):
class MyCell: UICollectionViewCell {
#IBOutlet var player:EYPlayerHUDView!
override func prepareForReuse() {
super.prepareForReuse()
// stop your player here
// set your label text = ""
}
}
After doing so, you can update the EYPlayerHUDView in cellForItemAt without instantiating it and without adding it as new view:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifer, for: indexPath) as? MyCell else {
return nil
}
if let allPlayers = self.allPlayers {
let player:EYPlayer = allPlayers[indexPath.row]
cell.player.updatePlayerHUD(player: player)
}
return cell
}
(Code untested)
Make custom UICollectionView class and implement prepareForReuse to clear the content if needed.
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
This label seems to return nil, even though I have the reuseIdentifier and tag set properly.
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var identifier: String = "CollectionCell"
var cell: UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) as! UICollectionViewCell
// Configure the cell
//save till later, when images are actually present
//var cellItem1 = hostManager[indexPath.row * 2]
let label:UILabel = cell.viewWithTag(1) as! UILabel
return cell
}
The program breaks where the label is set = to the viewWithTag. I have no custom class set for the cell, just the prototype. The tag is set on the storyboard. Getting an error "EXC_BAD_INSTRUCTION...". Any help would be appreciated, Thanks!
Try removing this line from viewDidLoad:
self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
I have just created a sample project with your code and for me it works. Although you shouldn't force unwrap.
Make sure you have the correct setup in your storyboard:
Check if your collectionViewCell is setup correctly:
And set the tag of your label:
Here is the sample project
I have created a UITableView and a subclass of UITableViewCell using code and it displays perfectly fine untill I select the cell.
The textLabel of the cell would shift rightwards or not shift sometimes
Image Representation of the problem before selection
Image representation of the problem after selection
Relevant Code
class MyCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
// here I fixed the image at a specific point
self.imageView?.bounds = CGRectMake(0, 0, 100, 125)
self.imageView!.frame = CGRectMake(0, 0, 100, 125)
self.imageView?.contentMode = .ScaleAspectFill
} }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = MyCell(style: UITableViewCellStyle.Default, reuseIdentifier: "FeedCell")
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: MyCell, atIndexPath indexPath: NSIndexPath) {
let item = self.items[indexPath.row] as MWFeedItem
cell.textLabel?.text = item.title
cell.textLabel?.font = UIFont.systemFontOfSize(12.0)
cell.textLabel?.numberOfLines = 0
}
You should really define your own image view and text label (with different names) in your subclass and apply constraints to lay them out in relation to the size of the cell, then set the row height in the controller so that things are displayed appropriately.
Even in your first image the size of images is incorrect so you have a mismatch configuration between the cell and the controller. And the properties you're currently using should be considered private private in terms of their size and position because you don't own the implementation which sets those features of the views.