Cells are not populating in second collection view inside of table - swift

I am new to coding and I am losing my mind with my current problem. I have a table view controller with 7 cells. I have 4 collection views in 7 of the cells. I have labels in the other three. I am trying to get my first two collection views to work so I can attack the same approach to add the other two. I am currently only able to get the cells of my first collection view (in cell 2) two populate. I don't know how to get the cells of the second collection view to populate.
Here is the code for the table view controller:
import UIKit
class HomeTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var t10MacInfCollectionView: UICollectionView!
#IBOutlet weak var t10MicroInfCollectionView: UICollectionView!
let T10Mac = "T10Mac"
let T10Mic = "T10Mic"
override func viewDidLoad() {
super.viewDidLoad()
t10MacInfCollectionView.delegate = self
t10MicroInfCollectionView.delegate = self
t10MacInfCollectionView.dataSource = self
t10MicroInfCollectionView.dataSource = self
self.view.addSubview(t10MicroInfCollectionView)
self.view.addSubview(t10MicroInfCollectionView)
t10MacInfCollectionView.reloadData()
t10MicroInfCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.t10MacInfCollectionView {
return 10
}
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.t10MacInfCollectionView {
let cellA = collectionView.dequeueReusableCell(withReuseIdentifier: T10Mac , for: indexPath) as! T10MacroCollectionViewCell
return cellA
}
else {
let cellB = collectionView.dequeueReusableCell(withReuseIdentifier: T10Mic , for: indexPath) as! T10MicroCollectionViewCell
return cellB
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == self.t10MacInfCollectionView {
return CGSize(width: 125.0, height: 225.0)
}
else {
return CGSize(width: 125.0, height: 225.0)
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
}
I am literally so frustrated. If someone could please help, I will be so thankful. Thank you guys for the help.

In the viewDidLoad() func: delete
self.view.addSubview(t10MicroInfCollectionView)
self.view.addSubview(t10MicroInfCollectionView)
The viewDid should now look like:
override func viewDidLoad() {
super.viewDidLoad()
t10MacInfCollectionView.delegate = self
t10MicroInfCollectionView.delegate = self
t10MacInfCollectionView.dataSource = self
t10MicroInfCollectionView.dataSource = self
t10MacInfCollectionView.reloadData()
t10MicroInfCollectionView.reloadData()
}

Related

How to Navigate to new View Controller from collection view cell? In Swift

I have two View controllers(VC-1, VC-2).
View controller 1 is having a table view and further that table view is consists of 4 collection views. I want to navigate to new VC(VC-2). But unable to get "self.storyboard.instantiateViewController" in didSelect method of collection View.
So now how I can navigate to VC-2
You should use delegate. you can create a protocol and define a method for routing and implement it into VC1
You can use the below sample code.
This code is using closure syntax
class FirstVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell_Identifier") as! TableCell
cell.configureCell(data: ["Your", "Data"])
cell.didSelectRow = { data in
// Goto second view controller
let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondVC")
self.navigationController?.pushViewController(vc!, animated: true)
}
return cell
}
}
class TableCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var colView: UICollectionView!
var didSelectRow: ((_ data: String) -> Void)? = nil // Closure
var arrData = [String]()
func configureCell(data: [String]) {
// Setup CollectionView data
self.arrData = data
self.colView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.arrData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CELL_IDENTIFIER", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let data = self.arrData[indexPath.row]
didSelectRow?(data)
}
}

How can l put TableView inside CollectionViewCell?

I have a tableView with several cells (created by MVVM-architecture).
In ViewController I fill my tableView like this:
tbv.registerCells(
withModels:
FirstViewModel.self,
SecondViewModel.self,
ThirdViewModel.self)
My task is to put my TableView in one cell of CollectionView. I thought l have to create CollectionView in my ViewController, after it create CollectionViewCell and CollectionCellViewModel, but how to do it exactly I don't understand.
If you know, how to make it, help.
How I have several tableviews in collection views in one of my apps. First I have a view controller in which I build my collection view. As usually proposed in the new design guidelines, I have the Collection View delegate and data source in an extension of this view controller.
In your view controller you define a delegate and data source for your table view. Preferably, this is a different class. I would not have the tableview data source and delegate also in the same view controller as your collection view.
class WorkoutSettingsViewController: UIViewController, LoadWorkoutSettings {
//MARK: - Properties
//Used variables
//Used constants
private let settingsDelegate = SettingsTableViewDelegate()
The extension would then look like this.
extension WorkoutSettingsViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
//Whatever sets your sections
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//Whatever sets your rows per section
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Workout Settings", for: indexPath) as! SettingsCollectionViewCell
settingsDelegate.workoutTitleLabel = [countdown, mainView, spokenMessage]
settingsDelegate.mainContentLabel = getSettingsContent()
cell.settingsTableView.delegate = settingsDelegate
cell.settingsTableView.dataSource = settingsDelegate
cell.settingsTableView.reloadData()
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
//Whatever you need as header or footer
}
The delegate does exactly what you would like the table view data source and delegate to do.
class SettingsTableViewDelegate: NSObject, UITableViewDataSource, UITableViewDelegate {
//MARK: - Properties
//Used variables
var workoutTitleLabel = [String]()
var mainContentLabel = [String]()
var selectedSetting: ((Int) -> ())? = .none
private var secondaryContentLabel = [String]()
//Used constants
private let onTitle = NSLocalizedString("ON", comment: "Localized on title")
private let offTitle = NSLocalizedString("OFF", comment: "Localized off title")
private let fontColorBlack = UIColor(red: 20.0/255.0, green: 20.0/255.0, blue: 19.0/255.0, alpha: 1.0)
private let fontColorRed = UIColor(red: 255.0/255.0, green: 96.0/255.0, blue: 89.0/255.0, alpha: 1.0)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
workoutTitleLabel.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Settings Cell") as! WorkoutTableViewCell
cell.workoutTitle.text = workoutTitleLabel[indexPath.row]
cell.mainContent.text = mainContentLabel[indexPath.row]
cell.secondaryContent.text = ""
(mainContentLabel[indexPath.row] == offTitle) ? (cell.mainContent.textColor = fontColorRed) : (cell.mainContent.textColor = fontColorBlack)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
selectedSetting?(indexPath.row)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
61
}
}
Your collection view cell should look like this.
class SettingsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var settingsTableView: UITableView!
}
This should then work. If you need to have a callback from the table view delegate / data source to your view controller managing your collection view, you can use a closure. In the example table view delegate the closure is called selectedSettings. In your view controller in viewDidLoad you define the call back for instance like this:
override func viewDidLoad() {
super.viewDidLoad()
settingsDelegate.selectedSetting = { [unowned self] selection in
startSettingsMenu(for: selection)
}
}
The result looks like this.
Kind regards,
MacUserT
In Tableview each row you can load UITableViewCell with pass collectionviewdata
//View Controller
var collectionView1Data = ["cell1", "cell2"]
var collectionView2Data = ["cell1", "cell2"]
//UITableviewDelegate Datasource
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//.....
if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellID") as? TableviewCell
cell.collectionData = collectionView1Data /// Collectionviewdata
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellID") as? TableviewCell
cell.collectionData = collectionView2Data
return cell
}
}
==============================
Each Tableviewcell contains CollectionView
//UITableViewCell
class TableviewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
var collectionData: [String]? {
didSet {
guard collectionData != nil else {
return
}
collectionView.reloadData()
}
}
override func awakeFromNib() {
super.awakeFromNib()
collectionView.register(UINib(nibName: "collectionViewCell", bundle: nil), forCellWithReuseIdentifier: "collectionViewCell")
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension TableviewCell: UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
collectionData.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as? collectionViewCell
cell...
return cell
}
}

UICollectionView first reusable table cell not showing up

I am working on a game right now and my level selection isn't working right.
The first cell in the collection view won't show up and I can't figure out why.
Here is what it looks like:
Picture of collection view with missing cell
And here is my code for the UICollectionViewController:
the reuse IdentifierList is a list of strings that corresponds to the cells in the storyboard version of this. and I have already checked that they are all spelled correctly.
The one missing is the "MyCell" cell.
class UICollectionCollectionViewController: UICollectionViewController {
var reuseIdentifierList = ["MyCell",
"MyCell2",
"MyCell3",
"MyCell4",
"MyCell5",
"MyCell6",
"MyCell7",
"MyCell8",
"MyCell9",
"MyCell10",
"MyCell11",
"MyCell12",
"MyCell13",
"MyCell14",
"MyCell15",
"MyCell16",
"MyCell17",
"MyCell18"
]
override func viewDidLoad() {
super.viewDidLoad()
reuseIdentifier = reuseIdentifierList[0]
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return reuseIdentifierList.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierList[indexPath.item], for: indexPath)
if indexPath.item != indexPath.startIndex {
cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierList[indexPath.item], for: indexPath)
}else{
cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierList[0], for: indexPath)
}
print(indexPath.item)
print(reuseIdentifierList[indexPath.item])
// Configure the cell
return cell
}
#IBAction func unwindToViewControllerLevel (sender: UIStoryboardSegue){
}
}
Thanks in advance
There is no point in creating that many cells. Just have an array to serve as your data source. In your case, it looks like you want your cells to have a button with numbers in order.
class UICollectionCollectionViewController: UICollectionViewController {
// let dataSourceArray = [Int](1...20) // [1, 2, 3 ..., 20]
// EDIT -- SegueId
let dataSourceArray = [(name: "1", segueId: "segueId1"), (name: "2", segueId: "segueId2"), (name: "3", segueId: "segueId3")]
let cellId = "customCellId"
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.register(CustomCell.self, forCellWithReuseIdentifier: cellId)
}
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return dataSourceArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
let item = dataSourceArray[indexPath.item]
cell.button.setTitle(item.name, for: .normal)
let segueId = item.segueId
// use segue id to perform different segues
return cell
}

pass data from UITableViewCell to UIViewController

I have UITableViewCell and I want to send the indexPath.row number to UIViewController using didSet, but xcode gives me an error when i use the value for other things (in UIViewController) says that the value is nil error: unexpectedly found null when unwrapping an optional value.
But if I print in the variable in UIViewController the value appears.
What i do? Thanks.
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet{
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
cell.LabelData.text! = "number \(indexPath.row)"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
ViewController() is just an instance of your ViewController. What you're doing when you say ViewController() is you're creating a new ViewController, rather than accessing the one you're looking for. If you want the indexPath.row, you need to send it to the actual VC, not just an instance of it.
You need to keep in mind that not all data is loaded instantly and at the same time, also that it does not always load in the order that you expect it to. It is possible that you are asking for the data before it is even assigned. Try
import UIKit
class TableViewCellCentral: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var CollectionData: UICollectionView!
var send = Int() {
didSet {
ViewController().reload = send
}
}
override func awakeFromNib() {
super.awakeFromNib()
CollectionData.dataSource = self
CollectionData.delegate = self
CollectionData.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
if indexPath.row != nil {
cell.LabelData.text! = "number \(self.indexPath.row)"
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = CollectionData.dequeueReusableCell(withReuseIdentifier: "CellData", for: indexPath) as! CollectionViewCellData
send = indexPath.row
CollectionData.reloadData()
}
}
I am only printing if the value is not nil! Let me know if you have more questions, or let us know if my solution is not working. =)

Why does my UICollectionViewController not show anything?

I'm trying to make a UICollectionViewController show a grid of cells (in which I'll later add text, likely as textViews if possible). I have:
class GridViewController : UICollectionViewController{
//(NOW GONE) #IBOutlet weak var gridViewTable = UICollectionViewController()
let arr1 : [String] = []
let arr2 : [String] = []
override func viewDidLoad(){
super.viewDidLoad()
self.collectionView!.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "gridCell")
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 4
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath as IndexPath)
cell.backgroundColor = UIColor.red
return cell
}
}
I used the interface builder to connect white where the cells will go to the gridViewTable. Nothing shows up at all, even tho it runs and compiles. How can I get the cells to show?
please use these code:
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 4
}
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: "gridCell", for: indexPath as IndexPath)
cell.backgroundColor = UIColor.red
return cell
}
You don't need the outlet for a UICollectionViewController, the class itself takes care of that.
Also, make sure that the view controller's class in Interface Builder is set to GridViewController in the Identity Inspector (3rd tab from the left in the right-most pane).