UICollectionView displays empty and doesn't show any cells - swift

I am just testing the code to see if it can load the collection view. But id doesn't show anything. Please look at the code below and let me know where I am wrong.
import UIKit
private let reuseIdentifier = "Cell"
class FeedController: UICollectionViewController {
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureUI()
collectionView.dataSource = self
collectionView.delegate = self
self.collectionView.reloadData()
}
//MARK: - Helpers
func configureUI() {
collectionView.backgroundColor = .white
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
}
//MARK:- UICollectionViewDataSource
extension FeedController {
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: reuseIdentifier, for: indexPath)
cell.backgroundColor = .systemRed
return cell
}
}
extension FeedController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
}

Set a breakpoint somewhere in viewDidLoad to test if it even calls any code of this class when running the app.
Normally you get an error when you set the dataSource and delegate in a UICollectionViewController, because these are already set by the controller. Because of this, move the extension lines to the main class and remove the extension.

You need to initialize FeedController using public init(collectionViewLayout layout: UICollectionViewLayout) UICollectionViewController initializer, else you have no layout assigned to the UICollectionView.
Wherever you are doing FeedController() you should do FeedController(collectionViewLayout: UICollectionViewFlowLayout()) or some custom UICollectionViewLayout.

Related

Xcode Swift error by casting my own collectionViewCell

I tried to create my own collectionViewCell. But by casting it in the cellForItemAt indexPath method it throws an error.
I don´t know why.
i hope you can help me.
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
// MARK: Outlets
#IBOutlet weak var testCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.testCollectionView.register(TestCollectionViewCell.self, forCellWithReuseIdentifier: "testCell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "testCell", for: indexPath) as! TestCollectionViewCell
cell.testLabel.text = "Hihi Test!"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 80)
}
}
This is the collectionViewCell class:
import UIKit
class TestCollectionViewCell: UICollectionViewCell {
var testLabel: UILabel = {
let label = UILabel()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(testLabel)
testLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
testLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And this is the error by starting the app:
First, register your cell into viewDidLoad method like that:
testCollectionView.register(UINib(nibName: "TestCollectionViewCell", bundle: Bundle(for: type(of: self))), forCellWithReuseIdentifier: "testCell")

Cant display image in UICollectionView cell

I need to display images in collection view cells but when I'm trying to do that I'm getting 10 empty cells and I don't know where im making mistakes
Here is my code of ViewController
class NewGalleryViewController: UIViewController {
var presenter: ViewToPresenterPhotoProtocol?
var builder: GalleryRequestBuilder?
#IBOutlet var collectionView: UICollectionView!
let reuseIdentifier = "customCVCell"
#objc func refresh() {
presenter?.refresh()
}
override func viewDidLoad() {
super.viewDidLoad()
self.setupPresenterIfNeed()
presenter?.viewDidLoad()
// Do any additional setup after loading the view.
}
func setupPresenterIfNeed() {
self.collectionView.backgroundColor = UIColor.white
if self.presenter == nil {
let presenter = GalleryPresenter()
presenter.view = self
self.presenter = presenter
self.builder = GalleryRequestBuilder()
}
}
}
extension NewGalleryViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.presenter?.photos.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! PhotoCollectionViewCell
KFImage.url(builder?.createImageUrl(name: (presenter?.photos[indexPath.item].name)!))
.onSuccess { result in
cell.imageView.image = result.image
}
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 180, height: 128)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 1.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 20.0
}
// MARK: - UICollectionViewDelegate protocol
private func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
}
}
extension NewGalleryViewController: PresenterToViewPhotoProtocol{
func onFetchPhotoSuccess() {
self.collectionView.reloadData()
self.collectionView!.collectionViewLayout.invalidateLayout()
self.collectionView!.layoutSubviews()
self.collectionView.refreshControl?.endRefreshing()
}
func onFetchPhotoFailure(error: String) {
print("View receives the response from Presenter with error: \(error)")
self.collectionView.refreshControl?.endRefreshing()
}
}
And Here is the code of cell
class PhotoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
I've checked the link I'm making request to and it works. So problem is not in link. Maybe I should reload items after getting images?
You should set your UICollectionView delegate and data source once the view is loaded:
override func viewDidLoad() {
super.viewDidLoad()
// Add this lines
collectionView.delegate = self
collectionView.dataSource = self
self.setupPresenterIfNeed()
presenter?.viewDidLoad()
}

UICollectionView in UIControl - delegate & datasource

I've added a UICollectionView to a UIControl (which is being called in a UITableViewController section header) and the UICollectionView is appearing (background color shows), but the datasource and delegate seem to be ignored - no cells are showing and a print statement in my dequeueReusableCell function isn't being called (but one in the UIControl init method is. Can you tell me what I'm missing here?
My UIControl:
// Stripped down code
final class My_Control: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(myCV)
}
private let myCV: Custom_CV = {
let cv: Custom_CV = Custom_CV()
return cv
}()
}
My Collection View:
final class Custom_CV: UIControl, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellIdentifier)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
cell.backgroundColor = .red
print("Building cell") // Not being called
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 72.0, height: 72.0)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//
}
private let cellIdentifier: String = "cellIdentifier"
private let collectionView: UICollectionView = {
let layout: UICollectionViewLayout = UICollectionViewLayout()
let collectionView: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = .white
return collectionView
}()
}
I think I'm missing something obvious, but I don't see it. I'm expecting to see 10 red squares and 10 print statements, but I get nothing there. But as I said - it's definitely being called because the a print statement in My_CV's init was being called, and I can see the .white background for the collectionview in My_Control.

Trying to Add a CollectionView to ResuableView Header like Instagram or SNapchat

I want to have a CollectionView in my Header that resembles that on Instagram and Snapchat for my main CollectionView which would be the feed. When I try to add the collectionview from the library and set the header as delegate and datasource after implementing the delegate methods, I still dont see anything in the header.
//let layout = UICollectionViewFlowLayout()
let headerCollection = UICollectionView(frame: CGRect(x: 0, y: 0, width: 50, height: 90), collectionViewLayout: UICollectionViewFlowLayout())
override func awakeFromNib() {
super.awakeFromNib()
// headerCollection.delegate = self
// headerCollection.dataSource = self
}
}
extension HeaderforFeed: UICollectionViewDataSource, UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return CollectionViewData.Dict_StrImg.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = UICollectionViewCell(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
cell.backgroundColor = .red
return cell
}
}```
Based on your code, I would think that the issue is you are not adding it to the header (I understand it as a header section inside your UICollectionView). If it's so, try add it at
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
}
Here, you would add your custom view with UICollectionView as UICollectionReusableView
I don't know if this could help you, but according to your question is what I understood
its fine i figured it out. I added the collectionview from the library unto my header in storyboard. Then i connected it as an outlet in my UICollectionReusableView class. I then made that class implement the delegate methods for a collectionview but for the one in the header.
Make the reusableview the delegate and datasource and it worked for me
// HeaderforFeed.swift
// finishedFeednStories
//
// Created by Guh Suck Yu Mada
// Copyright © 2019 Bumboklat. All rights reserved.
//
import UIKit
class HeaderforFeed: UICollectionReusableView {
//let layout = UICollectionViewFlowLayout()
#IBOutlet weak var storiesCollection: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
storiesCollection.delegate = self
storiesCollection.dataSource = self
}
}
extension HeaderforFeed: UICollectionViewDataSource, UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return CollectionViewData.Dict_StrImg.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "storiesCell", for: indexPath) as! StoriesCell
cell.storiesImg.image = Array(CollectionViewData.Dict_StrImg)[indexPath.row].value
cell.storiesLabel.text = Array(CollectionViewData.Dict_StrImg)[indexPath.row].key
return cell
}
}

Why won't my Collection View Cells display in the iPhone Simulator?

I am trying to programmatically create a Collection View with six cells. The iPhone Simulator in Xcode 8 told me that my build was successful. There is still an error though.
Any help spotting the bug or bugs that are causing my cells not to display in the Simulator is greatly appreciated. (I put the Collection View directly into the IB from the Object Library. Also, I want each cell to occupy the entire size of the Collection View, hence displayedCellDimensions, because the user will segue between cells when a forward or backward button is tapped.) Thank you!
import UIKit
class FluidIntakeMainMenuViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
//MARK: - Collection View Properties
#IBOutlet weak var ibCollectionView: UICollectionView!
var cellArray:[customCollectionViewCell] = Array(repeating: customCollectionViewCell(), count: 6)
let displayedCellDimensions = CGSize(width: 343, height: 248)
//MARK: - Xcode-generated Methods
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
ibCollectionView.dataSource = self
ibCollectionView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Collection View Methods
//Place cells in collection view and change the cell size
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView.visibleCells.isEmpty {
for cell in 0...cellArray.count {
collectionView.addSubview(cellArray[cell])
return CGSize(width: 343, height: 248)
}
}
return CGSize(width: 343, height: 248)
}
//Register a new cell
func registerCell(_ collectionView: UICollectionView) {
for _ in 0...cellArray.count {
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cellArray.count
}
...}
In your viewDidLoad() Try:
viewDidLoad() {
ibCollectionView.dataSource = self
ibCollectionView.delegate = self
}
Add this to the top of your class:
class FluidIntakeMainMenuViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
You must use these functions in your ViewController class:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {}