How to get UITableView row when user taps on UICollectionViewCell - ios

App Scheme-
As you can see from my App Scheme I have UITableView and inside UITableViewCells I have UICollectionView.
My question right now is how to get UITableView row when user taps on UICollectionViewCell?
I tried this but that doesn't work me:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
let main = ViewController()
if let tableViewcell = superview?.superview as? ExploreTableViewCell {
let indexPath = main.tableView.indexPath(for: tableViewcell)
print(indexPath)
}
}

To an extension of Subramanian Mariappan's concept and using delegate pattern to get informed in UIViewController about selection in collection view cell, please check your solution at https://github.com/sauvikapple/StackoverflowQ63802523.

Refactoring this viewController is on my todo list, but this should help out.
The key is setCollectionViewDataSourceDelegate() inside of willDisplayCell(). This lets you tap into the cell, and into the collectionView. And you can do something like set the tag to the row number.
TableView Cell:
import UIKit
class CollectionViewInsideTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.register(UINib(nibName: "cellNibName", bundle: nil), forCellWithReuseIdentifier: "cellIdentifier")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setCollectionViewDataSourceDelegate(dataSourceDelegate: UICollectionViewDataSource & UICollectionViewDelegate, forSection section: Int, multipleSelection: Bool) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.allowsSelection = true // If Needed
collectionView.allowsMultipleSelection = multipleSelection // If Needed
collectionView.scrollToItem(at: IndexPath(item: 31, section: 0), at: .right, animated: false)
self.collectionView.layoutSubviews()
}
}
Implementation:
cellforRow() {
let collectionCell = CollectionViewInsideTableViewCell // ETC
return collectionCell
}
extension TableViewController: UICollectionViewDelegate, UICollectionViewDataSource {
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? CollectionViewInsideTableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forSection: indexPath.section, multipleSelection: true)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = CollectionViewCell // ETC
return cell
}

Related

How to Navigate to another ViewController from Collectionview cell which is inside Tableview cell using delegate?

I am trying to navigate to another ViewController from Collectionview cell which is inside Tableview cell.
I am trying to achieve using delegate method but it's not navigating to intended viewcontroller.
Here is code that i have developed so far. I am using xib setup here.
// ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate,CustomTableViewCellDelegate {
#IBOutlet weak var tableView: UITableView!
var customTableViewCell = CustomTableViewCell()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
customTableViewCell.delegate = self
tableView.delegate = self
tableView.dataSource = self
self.tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.navigationBar.barTintColor = UIColor.black
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
self.navigationController?.navigationBar.tintColor = UIColor(red: 211/255, green: 86/255, blue: 50/255, alpha: 1.0)
}
//Delegate method
func passTheCurrent(tableIndex: Int, collectionViewIndex: Int) {
print("collectionViewIndex \(collectionViewIndex)")
let selectpile = ObjectSceneViewCtrl()
self.navigationController?.pushViewController(selectpile, animated: true)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let customCell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
return customCell
}
}
Here is CustomTableViewCell where i am defining delegate methods. I am calling delegate function inside collectionview didSelectItemAt method. But delegate is returning nil.
import UIKit
protocol CustomTableViewCellDelegate {
func passTheCurrent(tableIndex: Int, collectionViewIndex: Int)
}
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
var delegate: CustomTableViewCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(UINib.init(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CollectionViewCell")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension CustomTableViewCell : UICollectionViewDelegate {}
extension CustomTableViewCell : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath as IndexPath) as! CollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.passTheCurrent(tableIndex: 0, collectionViewIndex: indexPath.item)
}
}
When i set break point, delegate is returning nil. What is wrong with this setup. please help me out.
do the following simple steps this may helps you
1- in your cellForRowAt method assign delegate to your cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let customCell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell
customCell.delegate = self
return customCell
}
2- in your CustomTableViewCell class update your didSelectItemAt method with following code
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let del = self.delegate
{
del.passTheCurrent(tableIndex: 0, collectionViewIndex: indexPath.item)
}
}
Basically what we are doing now 1st we assigning delegate to cell on each index. 2nd in table cell class first we checking is delegate confirmed then pass the data to parent controller class. 😊

tvOS: Unable to scroll through UICollectionView items when it is implemented like this: UICollectionView inside UITableView

I have implemented this:
By following this tutorial.
Here's the problem:
I am unable to scroll through the collection items.
I think this has something to do with the fact that the project I followed is for iOS and my project is for tvOS.
I've found a somewhat similar question. An answer linked to this GitHub Repo whose implementation doesn't seem that different from mine.
Here's the relevant code:
ViewController.swift
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell =
tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as? TableViewCell
else {
fatalError("Unable to create explore table view cell")}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140
}
}
tableViewCell.swift
class TableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.delegate = self
collectionView.dataSource = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
extension TableViewCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 50
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// For some reason he chose the measures of collectionViewCell and substracted 2
return CGSize(width: 139, height: 64)
}
// Highlight the current cell
// This doesn't work
func collectionView(_ collectionView: UICollectionView, didUpdateFocusIn context: UICollectionViewFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
if let pindex = context.previouslyFocusedIndexPath, let cell = collectionView.cellForItem(at: pindex) {
cell.contentView.layer.borderWidth = 0.0
cell.contentView.layer.shadowRadius = 0.0
cell.contentView.layer.shadowOpacity = 0.0
}
if let index = context.nextFocusedIndexPath, let cell = collectionView.cellForItem(at: index) {
cell.contentView.layer.borderWidth = 8.0
cell.contentView.layer.borderColor = UIColor.orange.cgColor
cell.contentView.layer.shadowColor = UIColor.orange.cgColor
cell.contentView.layer.shadowRadius = 10.0
cell.contentView.layer.shadowOpacity = 0.9
cell.contentView.layer.shadowOffset = CGSize(width: 0, height: 0)
collectionView.scrollToItem(at: index, at: [.centeredHorizontally, .centeredVertically], animated: true)
}
}
}
In a separate project, I have implemented a collectionView independently. I.e: It was not embedded inside of a tableView. And it works just fine.
I copied the code from that project that highlights the selected cell and added it to the tableViewCell.swift but it had no impact at all.
So my question is:
Why am I unable to select a cell and/or scroll through the
collectionView?
Found the answer here:
By denying the focus of the table cell, the Focus engine will
automatically find the next focusable view on the screen. And in your
case, that is the collection view’s cell.
func tableView(_ tableView: UITableView, canFocusRowAt indexPath: IndexPath) -> Bool {
return false
}

UICollectionView inside of UITableViewCell

I am attempting to set a CollectionView inside of a TableViewCell. I have read through a hand full of stack questions, tuts, and videos and so far I have what appears to be the correct method but my collection view is still not loading into my table view cell.
Code:
import UIKit
class TheaterCell: UITableViewCell {
#IBOutlet var theaterName: UILabel!
#IBOutlet var theaterLocation: UILabel!
#IBOutlet var showtimesCollection: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
showtimesCollection.delegate = self
showtimesCollection.dataSource = self
showtimesCollection.reloadData()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension TheaterCell: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = showtimesCollection.dequeueReusableCell(withReuseIdentifier: "timeCell", for: indexPath) as! TimeCell
cell.time.text = "1:00"
return cell
}
}
The Tableview loads from the ViewController and is displaying its cells and elements but the collection view is not loading within the cell.
This is working for me, I think the problems comes from the way you register your cell
class YourCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
registerCell()
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
func registerCell() {
collectionView.register(TimeCell.self, forCellWithReuseIdentifier: "cell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TimeCell
cell.time.text = "1:00"
return cell
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
What I do, I use storyboard and setting the delegates & datasource from Storyboard by dragging into the classes.
a) Set TableView's delegates & datasource to ViewController
b) Set CollectionView's delegates & datasource to TableViewCell(TheaterCell)
ViewController Code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
extension ViewController:UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let theaterCell:TheaterCell = tableView.dequeueReusableCell(withIdentifier: "TheaterCell", for: indexPath) as! TheaterCell
theaterCell.reloadCollectionView()
return theaterCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
}
TheaterCell Code:
class TheaterCell: UITableViewCell {
#IBOutlet var showtimesCollection: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
}
func reloadCollectionView() -> Void {
self.showtimesCollection.reloadData()
}
}
extension TheaterCell: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = showtimesCollection.dequeueReusableCell(withReuseIdentifier: "timeCell", for: indexPath) as! TimeCell
cell.time.text = "1:00"
return cell
}
}
TimeCell Code:
class TimeCell: UICollectionViewCell {
#IBOutlet var time: UILabel!
}
Here is the output:
NOTE: IF YOU ARE NOT USING STORYBOARDS AND YOU MAKE COLLECTIONVIEW OR TABLE FROM CODE ONLY, THEN YOU HAVE REGISTER YOURS CELL AS:
A) TheaterCell must be registered into ViewController class
B) TimeCell must be registered into TheaterCell class

create collectionView when tapped on a button

Hi , how can I make this using a collection view ?
or when I tap on a button , It'll create a collectionView in my view controller .
Actually I want to add a collection view but I want the number of it to be dynamically cause I'm getting it's count from a server .
Please help me .
try this,I hope this will help you,
//viewcontroller.swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
return cell
}
//Tableviewcell.swift
class TableViewCell: UITableViewCell,UICollectionViewDelegate,UICollectionViewDataSource{
#IBOutlet var collectionview2: UICollectionView!
#IBOutlet var collectionview1: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionview1.dataSource = self
collectionview1.delegate = self
collectionview2.dataSource = self
collectionview2.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(collectionView == collectionview1){
return 5
}else{
return 10
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == collectionview1){
let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
return cell
}else {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath)
return cell1
}
}
}
Finally set "collectionview1" scroll direction has Horizontal and set "collectionview2" scroll direction has Vertical.

UITableView inside UICollectionView -> [error] unexpectedly found nil while unwrapping tableView

I have a UITableView inside each cell of a UICollectionView.
I referenced the table view to a FeedCell class, which is a class for each cell in the collection view. However, I got an error saying
fatal error: unexpectedly found nil while unwrapping an Optional value
when trying to access the tableView object in the FeedCell class. I triple checked that I referenced the table view from the storyboard correctly, so I'm assuming there's something else that's causing it to be nil, but I'm not sure what it is. Does anyone have a clue about how to fix this?
This is my VC where both the collection view and the table view lies.
class HomeViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isTranslucent = false
collectionView.register(FeedCell.self, forCellWithReuseIdentifier: "FeedCell")
}
// for feedcell and its collection view
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeedCell", for: indexPath) as! FeedCell
cell.backgroundColor = backgrounds[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
guard let collectionViewCell = cell as? FeedCell else { return }
collectionViewCell.setTableViewDataSourceDelegate(dataSourceDelegate: self, forRow: indexPath.row)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}
// conform to tableview protocol for hometable
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return images[tableView.tag].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell", for: indexPath)
cell.imageView?.image = images[tableView.tag][indexPath.item]
return cell
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: animated)
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: animated)
super.viewWillDisappear(animated)
}
}
And here's a cell of the collection view where I reference the table view.
class FeedCell: BaseCollectionViewCell{
#IBOutlet weak var tableView: UITableView!
override func setupViews() {
super.setupViews()
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
}
extension FeedCell {
func setTableViewDataSourceDelegate
<D: UITableViewDataSource & UITableViewDelegate>
(dataSourceDelegate: D, forRow row: Int) {
# ERROR!
tableView.delegate = dataSourceDelegate
tableView.dataSource = dataSourceDelegate
tableView.tag = row
tableView.reloadData()
}
}
On this line:
(dataSourceDelegate: D, forRow row: Int)
You cast it as the variable: D
Use this instead:
tableView.dataSource = D
tableView.delegate = D

Resources