UICollectionView cells not displaying while UICollectionView background is - ios

this is my class for ImageController (a ViewController)
Only the background of the collection view is displaying while the cells in it are not. Any help? Is there something I didn't initialize correctly?
Here is the class:
class ImageController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
let reuseIdentifier = "imageCell"
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! ImageCell
cell.myImage.image = unknown //name of image, isn't the cause of error
return cell
}
}

You should add in the viewDidLoad():
collectionView.delegate = self
collectionView.dataSource = self
Also, try to debug the methods (add breakpoints and check if they are reachable).
Hope this helped.

If you dont want to use the lines of code mentioned above, just right click on the collectionView and drag to ViewController Scene the yellow space and select delegate and dataSoruce.

Related

IBOutelt found nil when UICollectionViewCell is load

I am studying how to create a simple app without storyboard and I have a problem:
I created a XIB called HomeViewController, inside it has a UICollectioView and made the registration of the cell in the viewDidLoad().
after that, I created a cell called HomeCollectionViewCell, put the identifier as "cell", in the cell it has a UILabelOutlet, that is referenced in the .swift file.
After setting the delegate and the datasource, it has the mandatory methods of the datasource, when making the cell configuration and calling the label by setting any text it returns nil. I don't know why this is happening, I've seen several videos on YouTube and none has solved the problem. Can anybody help me?
HomeViewController
class HomeViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var info = ["Image"]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(HomeCollectionViewCell.self, forCellWithReuseIdentifier:
"cell")
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection
section: Int) -> Int {
return info.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath:
IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for:
indexPath) as? HomeCollectionViewCell
cell?.teste.text = "test"
return cell!
}
}
HomeCollectionViewCell
class HomeCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var teste: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
}
That's because you have to register cell's nib not just class:
collectionView.register(UINib(nibName: "HomeCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "cell")

The currencyLabel outlet from the ViewController to the UILabel is invalid. Outlets cannot be connected to repeating content

I inserted Label into CollectionView cell but when I made outlet this error appeared.
error: The currencyLabel outlet from the ViewController to the UILabel is invalid. Outlets cannot be connected to repeating content
class ViewController: UIViewController {
var currency = Currency.getCurrency()
#IBOutlet var currencyLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return currency.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "currencyCell", for: indexPath) as! CurrencyCollectionViewCell
let currencyList = currency[indexPath.row]
currencyLabel.text = "\(currencyList.currency) \n \(currencyList.cash)"
return cell
}
}
You need to create IBOutlet of your currencyLabel in CurrencyCollectionViewCell class, and use it like
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "currencyCell", for: indexPath) as! CurrencyCollectionViewCell
let currencyList = currency[indexPath.row]
cell.currencyLabel.text = "\(currencyList.currency) \n \(currencyList.cash)"
return cell
}
You have made a simple mistake.
You should make below outlet in CollectionViewCell not in your ViewController.
#IBOutlet var currencyLabel: UILabel!

How to push a new UICollectionViewController to the navigationController inside a cell of cells of cells

I have build a UICollectionViewController programmatically which returns 4 cells. HomeCell, TrendingCell, SubscriptionCell and AccountCell.
All 4 cells should be different and you can scroll them horizontally. <--->.
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout{
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.register(HomeCell.self, forCellWithReuseIdentifier: homeCellId)
collectionView?.register(TrendingCell.self, forCellWithReuseIdentifier: trendingCellId)
collectionView?.register(SubscriptionCell.self, forCellWithReuseIdentifier: subscriptionCellId)
collectionView?.register(AccountCell.self, forCellWithReuseIdentifier: accountCellId)
}
}
Lets take the first cell of the HomeController called HomeCell to illustrate my problem. Homecell has three custom cells called VideoCell, CategoryCell and UserSearchCell.
class HomeCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
let searchId = "sarchId"
let scrollId = "scrollId"
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
cv.dataSource = self
cv.delegate = self
return cv
}()
override func setupViews() {
super.setupViews()
.....
// register three different cells within HomeCell
collectionView.register(VideoCell.self, forCellWithReuseIdentifier: cellId)
collectionView.register(CategoryCell.self, forCellWithReuseIdentifier: scrollId)
collectionView.register(UserSearchCell.self, forCellWithReuseIdentifier: searchId) //
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In HomeCell I register the UserSearchCell as third cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 0 {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoId", for: indexPath)
} else if indexPath.item == 1{
cell = collectionView.dequeueReusableCell(withReuseIdentifier: categoryId, for: indexPath)
}else {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: searchId, for: indexPath)
}
return cell
}
If I click on that element my goal is to push a new ViewController to the navigationController. But I have no access and don't know how to change the view within that nested structure. I tried the didSelectItem method within HomeCell class and was able to print something the console when clicking the third cell but couldn't change the view.
class HomeCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 2 {
print(123)
}
....
}
Please help. Is there a way to change the View within the didSelectItem method of HomeCell ??
You need to write a protocol to refer back to your HomeController.
protocol HomeCellProtocol {
func pushNavigation(_ vc: UIViewController)
}
add write delegate property to HomeCell class with
class HomeCell: ..... {
var delegate: HomeCellProtocol?
}
and make HomeController confirm to HomeCellProtocol with
extention HomeController: HomeCellProtocol {
func pushNavigation(_ vc: UIViewController) {
self.navigationController?.pushViewController(vc, animated: true)
}
}
and when you setup your HomeCell you need to set your delegate in HomeController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: homeCellId, for: indexPath) as HomeCell;
cell.delegate = self // Set the delegate
return cell
}
finally, you can call push function within HomeCell with
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 2 {
let vc = UIViewController();
self.delegate?.pushNavigation(vc);
}
}

Using CollectionView in UIView with xib file

i'm doing with this, i want to use CollectionView, but i haven't seen prototype cell, and don't know how to use CollectionView in this case, can someone help me ?
I try to use like this way but it take alot of time and hard to manage than UICollectionView
The main way to use UICollectionView is by managing the logic programmatically.
First, create a new class which inherits from UICollectionViewCell. Choose if you want to include a xib to easily design your cell:
Design your cell with Interface Builder or programmatically.
Create your main view controller including a xib (or a storyboard) with the collection view inside and link it to the associated class via Interface Builder. Alternatively you can add a collection view programmatically to your UIViewController
Make the target view controller conform to the UICollectionViewDelegate and UICollectionViewDataSource protocols by declaring them after the father class:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
//...
}
Register the associated nib or the class for your cell in the viewDidLoad method and associate the datasource and delegate protocols to the view controller class:
let cellIdentifier = "cellIdentifier"
override func viewDidLoad() {
super.viewDidLoad()
//if you use xibs:
self.collectionView.register(UINib(nibName:"MyCollectionCell", bundle: nil), forCellWithReuseIdentifier: cellIdentifier)
//or if you use class:
self.collectionView.register(MyCollectionCell.self, forCellWithReuseIdentifier: cellIdentifier)
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
Implement the methods declared in the UICollectionViewDelegate and UICollectionViewDataSource protocols :
let objects = ["Cat", "Dog", "Fish"]
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.objects.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as! MyCollectionCell
//in this example I added a label named "title" into the MyCollectionCell class
cell.title.text = self.objects[indexPath.item]
return cell
}
Run your app in the simulator (or on a real device) and.. Et voilà! :)
For more info: https://developer.apple.com/reference/uikit/uicollectionview
ok first you must have the IBOutlet of your collection view and implements the methods like this
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
#IBOutlet var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
count = 9;
let nib = UINib(nibName: "yourItemView", bundle: nil)
collectionView.registerNib(nib, forCellWithReuseIdentifier: "yourItemView")
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
ok in the function you add a xib file, next you must create that extend from UICollectionViewCell, and when you finish this you must override the next methods
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return count
// the numbers of items
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {//size of your item for screen sizes
let wsize = UIScreen.mainScreen().bounds.size.width
switch(wsize){
case 414:
return CGSize(width: 190, height: 102)
case 375:
return CGSize(width: 190, height: 102)
case 320:
return CGSize(width: 174, height: 102)
default:
return CGSize(width: 174, height: 102)
}
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("yourItemView", forIndexPath: indexPath) as! yourItemView
return cell
}
and this is all, good luck

UICollectionView in a UICollectionViewCell

I am interested in having a collectionview as a part of a collection view cell but for some reason cannot figure out how this would be done. Where would I implement the necessary methods for the cells collectionview?
There's an article that Ash Furrow wrote that explains how to put an UICollectionView inside an UITableViewCell. It's basically the same idea when using it inside an UICollectionViewCell.
Everything is done programatically. No storyboards.
I added a UICollectionView inside my UICollectionViewCell. I also show how to add again a UICollectionViewCell inside the created UICollectionView to have this result
import UIKit
class CategoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let cellId = "cell"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let appsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
return collectionView
}()
func setupViews() {
backgroundColor = .blue
addSubview(appsCollectionView)
appsCollectionView.delegate = self
appsCollectionView.dataSource = self
appsCollectionView.register(AppCell.self, forCellWithReuseIdentifier: cellId)
addConstrainstWithFormat("H:|-8-[v0]-8-|", views: appsCollectionView)
addConstrainstWithFormat("V:|[v0]|", views: appsCollectionView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
return cell
}
}
class AppCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .red
}
}
My UICollectionViewController
import UIKit
class FeaturedAppsController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cell"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
collectionView?.backgroundColor = .white
collectionView?.register(CategoryCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
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(view.frame.width, 150)
}
}
The whole explanation can be found and was developed by "Let´s build that app": https://www.youtube.com/watch?v=Ko9oNhlTwH0&list=PL0dzCUj1L5JEXct3-OV6itP7Kz3tRDmma
This is too late for this answer but it might help others. This is an example of UICollectionView inside a UICollectionViewCell.
Lets start by having a mainCollectionView. Then on each cell of this collection create and initialize a new UICollectionView and right place to do that is in this following delegate of UICollectionView
func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath)
e.g I initialize the MainCollectionViewCell here and then MainCollectionViewCell handles the logic to create a new UICollectionView
guard let collectionViewCell = cell as? MainCollectionViewCell else { return }
collectionViewCell.delegate = self
let dataProvider = ChildCollectionViewDataSource()
dataProvider.data = data[indexPath.row] as NSArray
let delegate = ChildCollectionViewDelegate()
collectionViewCell.initializeCollectionViewWithDataSource(dataProvider, delegate: delegate, forRow: indexPath.row)
collectionViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
Here is the initializer on MainCollectionViewCell that creates a new UICollectionView
func initializeCollectionViewWithDataSource<D: protocol<UICollectionViewDataSource>,E: protocol<UICollectionViewDelegate>>(dataSource: D, delegate :E, forRow row: Int) {
self.collectionViewDataSource = dataSource
self.collectionViewDelegate = delegate
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .Horizontal
let collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: flowLayout)
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseChildCollectionViewCellIdentifier)
collectionView.backgroundColor = UIColor.whiteColor()
collectionView.dataSource = self.collectionViewDataSource
collectionView.delegate = self.collectionViewDelegate
collectionView.tag = row
self.addSubview(collectionView)
self.collectionView = collectionView
collectionView.reloadData()
}
Hope that helps !!
I did an example for this and put in on github. It demonstrates the use UICollectionView inside a UICollectionViewCell.
https://github.com/irfanlone/Collection-View-in-a-collection-view-cell
Easiest solution for collectionview inside collectionview using storyboard and Swift 5
Please refer this link for nested collectionview example
import UIKit
class ParentViewController:UIViewController,UICollectionViewDataSource,UICollectionViewDelegate {
//MARK: Declare variable
//MARK: Decalare outlet
#IBOutlet weak var outerCollectionView: UICollectionView!
#IBOutlet weak var pageControl: UIPageControl!
let outerCount = 4
//MARK: Decalare life cycle methods
override func viewDidLoad() {
super.viewDidLoad()
pageControl.numberOfPages = outerCount
}
//MARK: Collection View delegate methods
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return outerCount
}
//MARK: Collection View datasource methods
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OuterCell", for: indexPath) as! OuterCollectionViewCell
cell.contentView.backgroundColor = .none
return cell
}
//MARK:- For Display the page number in page controll of collection view Cell
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.outerCollectionView.contentOffset, size: self.outerCollectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.outerCollectionView.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
}
class OuterCollectionViewCell: UICollectionViewCell ,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var InnerCollectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
InnerCollectionView.delegate = self
InnerCollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InnerCell", for: indexPath) as! InnerCollectionViewCell
cell.contentView.backgroundColor = .green
return cell
}
}
class InnerCollectionViewCell: UICollectionViewCell{
}

Resources