UICollectionViewCell not shown properly - swift

I have the following code. For some strange reason, the cell is not registering properly and the cell is not rendered.
I expect there to be 5 purple cells but instead there is only red background.
class RateController: UICollectionViewController {
var user: User?
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .red
collectionView?.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = .purple
return cell
}
}

There's nothing wrong with your code. I pasted it right into a fresh project, defined the User class, made the necessary adjustments in the storyboard, and ran it:
So if there's a problem, it's somewhere else — not in that code!
I've been thinking about where else the problem could be; the problem you are describing would happen if you disabled the Flow layout in the storyboard and replaced it with an empty Custom layout, like this:
If you did that, set the Layout back to Flow.

Related

Improper width of cell in collectionview

[updated]
I have created collectionview containing cells with different captions and different widths. It works fine when I read collection on launch of application.
But when I add new cell during usage of the application it has standard, narrow, width.
When I again relaunch the application it will again have correct width.
After adding reloadData() it works fine for one cell. But when I have multiple cells they are drawn one on each other.
And here is the code:
override func viewDidLoad() {
super.viewDidLoad()
projectCollectionView.delegate = self
projectCollectionView.dataSource = self
projectCollectionView.register(UINib(nibName: "projectCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "projectCollectionViewCell")
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: projectCollectionViewCell.identifier, for: indexPath) as? projectCollectionViewCell
else {
return projectCollectionViewCell()
}
cell.projectButton.setTitle("a title", for: .normal)
projectCollection[indexPath.row].cellIndex = indexPath.row
cell.projectButton.sizeToFit()
cell.layer.bounds.size.width = cell.projectButton.layer.bounds.width
return cell
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
projectCollectionView.collectionViewLayout.invalidateLayout()
projectCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
var result: Int = 0
for i in 0...projects.count-1 {
if (projects[i].status>=2) {
result += 1
}
}
return result
}
When I remove the row: cell.projectButton.sizeToFit() it started to look like this:
try it :-
relod collectionview after adding element.
collectionview.reloaddata()
[edited]
add flowlayout to collectionview
add below code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let label = UILabel(frame: CGRect.zero)
label.text = textArray[indexPath.item]
label.sizeToFit()
return CGSize(width: label.frame.width, height: 32)
}
for more visit https://stackoverflow.com/a/53284536/12451658

UICollectionViewCell is not rounding corners inside UITableView

The problem is that when I have UICollectionView inside UITableViewCell - UICollectionViewCell cornerRadius function not working.
Code is very simple and it was always working for me when playing with UICollectionView.
extension ExploreTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ExploreCollectionViewCell
cell.thumbnail.layer.cornerRadius = 20
cell.thumbnail.clipsToBounds = true
return cell
}
Is it a bug or what? Cannot find any answer all day. Most of the people suggest to use contentView instead of the specific image inside the cell but that's not for me since I want only image to be rounded.
P.S this one works (but I want only image inside the cell to be rounded):
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = 30
self.clipsToBounds = true
}

Segue from selected collection view cell sends to wrong collection view

I am using swift. I'm trying to create a collectionView segue to lead to a new viewController.
I have a series of (lets say 8) different images and labels as an array within the collectionView, and the when selected, I want the user to be sent to another view controller (with 8 different possibilities - one for each cell). I have been able to get the app to build, but the behaviour from selecting a cell is wrong.
The first cell that is selected has no response, then the next cell initiates a segue - but to the previously selected one! Each time a different cell is selected, it segues to the previous selected cell. Can anyone help me correct this error?
I have used performSegue and pushViewController separately, following different tutorials on youtube, but each resolves to the same issue.
The various view controllers to segue to have been allocated their own storyboardID in the main.storyboard file. The initial view controller is embedded within a navigation controller, and each new veiwcontroller (to segue to) has been connected to the collection view of the main view controller.
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet var CollectionView: UICollectionView!
// created an array for labels
let NamesForSectionTitles = ["Overview","Canopy trees","Mid-story trees","Understory plants","Birds","Mammals","Ferns","Butterflys"]
// created list of images to be loaded in the collectionview
let sectionIconImages: [UIImage] = [
UIImage(named: "IMG_8750_landscape_night")!,
UIImage(named: "IMG_8789_Trees")!,
UIImage(named: "IMG_2185_Tree_Olearia")!,
UIImage(named: "_MG_9528_Herb_Flower")!,
UIImage(named: "IMG_3654-")!,
UIImage(named: "IMG_9892-2")!,
UIImage(named: "IMG_9496_Ferns_crozier")!,
UIImage(named: "IMG_7707_Butterfly")!,
]
override func viewDidLoad() {
super.viewDidLoad()
// load the data sources and delegate
CollectionView.dataSource = self
CollectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return NamesForSectionTitles.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->
UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
cell.SectionTitle.text = NamesForSectionTitles[indexPath.row]
cell.sectionImages.image = sectionIconImages[indexPath.row]
return cell
}
// tells the collection view that upon selecting a cell, show the next UIView controller, as suggested in storyboard name (main.storyboard property) - tutoral from https://www.youtube.com/watch?v=pwZCksvXGRw&list=PLPUDRZDcNNsMdyfZVw4CJDT1Wu8cYx_6E&index=7&t=0s
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
performSegue(withIdentifier: NamesForSectionTitles[indexPath.row], sender: self)
}
}
The viewer should see an image view with a label, that when selected takes them to a new collection view.
Can't Comment so posting an answer
I think
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) is causing the issue.
Please try changing that line to:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)

UICollectionView Cell not changing upon selecting

In my project, I have a UICollectionView. In the UICollectionView, I have a custom cell.
I am able to print the cell value when it is selected within "didSelectItemAt", however, if I try to edit the cell in any way within this method, it does not change.
I'm sure I'm missing something, any help would be appreciated!
#IBOutlet weak var collectionView: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return statValues.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCollectionViewCell", for: indexPath) as! customCollectionViewCell
cell.statLabel.text = statHeaders[indexPath.row]
cell.statLabel.textColor = UIColor(red:0.31, green:0.31, blue:0.31, alpha:1.0)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCollectionViewCell", for: indexPath) as! customCollectionViewCell
print(cell.statLabel.text)
cell.backgroundColor = UIColor.yellow
collectionView.reloadData()
}
When user selects a cell, the code is correctly printing the value of the indexPath, however the backgroundColor does not change.
My guess would be that you are creating a new instance of cell instead of using the one in the collectionView
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Change this line
let cell = collectionView.cellForItemAtIndexPath(indexPath: indexPath)
print(cell.statLabel.text)
cell.backgroundColor = UIColor.yellow
collectionView.reloadData()
}
Also, you should probably keep an external data model for your source of truth. If you have enough collectionViews that requires scrolling, when you scroll offscreen, your cells will be reused in a random order causing cells that you did not click to be yellow.
Create a seperate array such as
var selectedStatHeaders: Set<Int>()
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCollectionViewCell", for: indexPath) as! customCollectionViewCell
cell.statLabel.text = statHeaders[indexPath.row]
cell.statLabel.textColor = UIColor(red:0.31, green:0.31, blue:0.31, alpha:1.0)
// Reset/configure cell each reload
if selectedStatHeaders.contains(indexPath.row) { // Can also make this into a ternary
cell.backgroundColor = UIColor.yellow
} else {
cell.backgroundColor = UIColor.whit
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedStatHeaders.insert(indexPath.row)
collectionView.reloadItemsAtIndexPath(indexPath: indexpath)
}
Hmm... Doesn't make sense if the code is able to print but the background doesn't change color. Do you mean changing back from yellow to white? Anyway, just a hunch but I suspect it's because you are calling collectionView.reloadData() after your set the backgroundColor change.
https://developer.apple.com/documentation/uikit/uicollectionview/1618078-reloaddata
This causes the collection view to discard any currently visible
items (including placeholders) and recreate items based on the current
state of the data source object.

Wrong images loaded after scrolling in collectionView swift 3

I am having issues with my collectionView in Swift 3. I have found some tips on Stackoverflow, tried them out, but alas to no avail. Many mentioned to use the 'prepareReuse' method, but I could not get those to work in my code. After Scrolling down, and back up again, the images have changed. All the images are letters of the alphabet. So A,B,C are the first images to appear at the top of the view. If you scroll down, and back up, some random other letters have taken their place. My entire code is as follows:
import UIKit
class colViewController2: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var imageData: [String] = [String]()
var imageCounter: Int = 0
var userHasHieroglyph: NSArray = ["","","C","D","E","F","G","H","I","J","K","L","M","N","O","","Q","R","S","T","U","V","W","X","Y","Z"]
override func viewDidLoad() {
super.viewDidLoad()
imageData = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
for b in imageData {
if userHasHieroglyph.contains(b) {
let newHieroglyph = b.lowercased()
imageData[imageData.index(of: b)!] = "h-"+newHieroglyph
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellid", for: indexPath) as! MyImageCell
cell.backgroundColor = UIColor.white
var currImage:String = ""
currImage = self.imageData[self.imageCounter]
self.imageCounter += 1
if self.imageCounter >= self.imageData.count {
self.imageCounter = 0
}
cell.image.image = UIImage(named: currImage)
return cell
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 26
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 90, height: 90)
}
}
I hope I am missing some small bit of code to solve this problem, but after many hours of searching on Stackoverflow, and the internet, I still can not find a solution to this problem. If anyone has a solution or tip, it would be greatly appreciated!
Greetings
The issue is that you're using imageCounter as the index into your array of images, but incrementing it instead of using the indexPath.item. Remember that the UICollectionView will reuse UICollectionViewCell instances. Basically, it will only create cell instances for those that are on the screen. If a cell scrolls off the screen and a new one takes its place (e.g. if you have "A", "B", and "C" on the screen, and scroll down so you see "B", "C", "D", the UICollectionView will reuse the "A" cell for "D". This is a bit of an oversimplification, but more or less how it works). As such, the cellForItem call will give you the information about which cell is being displayed in the indexPath parameter. In this case, you can get rid of all of the self.imageCounter logic and instead do cell.image.image = UIImage(named: imageData[indexPath.row])
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellid", for: indexPath) as! MyImageCell
cell.backgroundColor = UIColor.white
cell.image.image = UIImage(named: imageData[indexPath.row])
return cell
}