Why won't my swift collection view show anything - swift

I want to make a simple collection view just showing some pictures but the cells wont show
import UIKit
final class HomePageViewController: UICollectionViewController {
// MARK: - Properties
override func loadView() {
super.loadView()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: self.view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
self.collectionView = collectionView
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.backgroundColor = .white
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(HomePageCell.self, forCellWithReuseIdentifier: "HomePageCell")
}
// MARK: - Private
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomePageCell", for: indexPath) as! HomePageCell
cell.Picture.image = UIImage(named: "songpic-1")
return cell
}
}
extension HomePageViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.size.width - 16, height: 200)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 8
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.init(top: 8, left: 8, bottom: 8, right: 8)
}
}
import UIKit
class HomePageCell: UICollectionViewCell {
#IBOutlet weak var Picture: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
let Picture = UIImageView(frame: .zero)
Picture.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(Picture)
NSLayoutConstraint.activate([
Picture.topAnchor.constraint(equalTo: self.contentView.topAnchor),
Picture.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
Picture.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
Picture.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor),
])
self.contentView.backgroundColor = .lightGray
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("Interface Builder is not supported!")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func prepareForReuse() {
super.prepareForReuse()
}
}

You can delete/comment your loadView() implementation and things should work just fine. You will still get a UICollectionView to work with.
The loadView() implementation is supposed to provide a UIView instance that's to be assigned to UIViewController.view property. In your implementation however, we are using it via self.view directly without assigning it first.
From UIViewController.loadView() docs -
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.
What to do if this still doesn't show up?
Check using View Hierarchy Debugger that at run time your collectionView has non-zero width & height values. If any of the width OR height is zero, you will run into this issue.

Related

UICollectionView displays empty and doesn't show any cells

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.

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.

CollectionView don't update visible cell

Good afternoon!
Faced with this problem, there is a collection in which cells in the whole screen
the cell is configured with data,
and there are events inside the cell that make the collection reload,
it is not possible to make a check, if the cell is now visible, it is not necessary to update it completely, but only part of the data, I do not yet understand how to do it, can someone be able to prompt?!))
Test project))
import UIKit
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionViwe: UICollectionView!
let dataSource = [1,2,3,4,5,6,7,8,9]
override func viewDidLoad() {
super.viewDidLoad()
collectionViwe.isPagingEnabled = true
collectionViwe.register(Cell.self, forCellWithReuseIdentifier: "Cell")
// Do any additional setup after loading the view.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
let text = String(dataSource[indexPath.row])
if cell.label.text != text {
cell.label.text = text
cell.label.backgroundColor = .random()
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return view.frame.size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return .zero
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.reloadData()
}
}
class Cell: UICollectionViewCell {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
label.backgroundColor = .red
addSubview(label)
label.frame = CGRect(x: 36, y: 36, width: 200, height: 100)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension CGFloat {
static func random() -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UInt32.max)
}
}
extension UIColor {
static func random() -> UIColor {
return UIColor(red: .random(),
green: .random(),
blue: .random(),
alpha: 1.0)
}
}

Adding WebView to CollectionView without using MainStoryboard

I've been working on CollectionView with ImageView in each cells. Now I'm wondering how to add WebView working the same way as ImageView. I want it working as an element in each cell, is it possible? In addition, I am not using storyboard.
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(WebCell.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)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height - 500)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class WebCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let StronaSzkolna: UIImageView = {
let webview = UIImageView()
webview.backgroundColor = UIColor.blue
webview.translatesAutoresizingMaskIntoConstraints = false
return webview
}()
func setupViews() {
addSubview(StronaSzkolna)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[v0]-16-|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":StronaSzkolna]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-16-[v0]-16-|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":StronaSzkolna]))
StronaSzkolna.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}