I have a CollectionView that is scrolling horizontally. I have custom CollectionViewCells that have inside a TableView with three cells. It looks like this:
[![Here is a example of how it looks][1]][1]
This is the main ViewController where I have the CollectionView
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.viewModel.numberOfItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ItemCell.reuseIdentifier, for: indexPath) as! ItemCell
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedItem = self.viewModel.items[indexPath.item]
}
}
And this is the ItemCell code that contains the tableview
class ItemCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func awakeFromNib() {
super.awakeFromNib()
self.tableView.delegate = self
self.tableView.dataSource = self
}
override func layoutSubviews() {
super.layoutSubviews()
self.tableView.allowsMultipleSelection = true
self.tableView.register(UINib(nibName: "DailySelectionViewCell", bundle: nil), forCellReuseIdentifier: DailySelectionViewCell.reuseIdentifier)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: DailySelectionViewCell.reuseIdentifier, for: indexPath) as! DailySelectionViewCell
switch indexPath.section {
case 0:
cell.descriptionLabel.text = "Item1"
case 1:
cell.descriptionLabel.text = "Item2"
default:
cell.descriptionLabel.text = "Item3"
}
return cell
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect.zero)
view.backgroundColor = UIColor.clear
return view
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
I want to click on the TableView cells that are inside the CollectionView cells. When I want to click on a TableViewCell, the touches are only registered on the CollectionViewCell and I can't click on any of the tableview cells inside the CollectionViewCell.
By default didSelectRowAt must work.
As an assumption DailySelectionViewCell may contains some views with user interaction, namely subclassed from UIControl: UIButton, UIDatePicker, UISegmentedControl and so on. In this case didSelectRowAt not work and this is correct behavior.
Related
I have a UICollectionView nested inside of a UITableViewCell. The collectionview inside of each tableviewcell section should return different data according to the section. Here is my code:
ViewController.swift
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
var categoryKeys: [String]?
let network = MediaNetworking()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// fetch data
network.fetchMedia()
tableView.delegate = self
tableView.dataSource = self
print("hello world")
}
func numberOfSections(in tableView: UITableView) -> Int {
self.categoryKeys = network.categoryKeys
return self.categoryKeys!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SectionTableViewCell
cell.theArray = network.sharedArray
cell.accessArray = network.accessArray
cell.backgroundColor = .purple
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
self.categoryKeys = network.categoryKeys
return self.categoryKeys?[section]
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 300
}
}
SectionTableViewCell.swift
class SectionTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var categoryKeys: [String]?
var theArray: [String: [Entity]]?
var accessArray: [Entity]?
#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)
// Configure the view for the selected state
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return accessArray!.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
cell.artistLabel.text = accessArray![indexPath.row].name
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeaderView", for: indexPath) as! SectionHeaderView
if indexPath.section < categoryKeys!.count {
let category = categoryKeys![indexPath.section]
sectionHeader.categoryLabel.text = category
}
return sectionHeader
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 400, height: 300)
}
}
Right now all the collectionview cells are returning the same values. Any ideas on what I might be missing?..
Did you try to call collectionView.reloadData() after changing the data arrays?
cell.theArray = network.sharedArray
cell.accessArray = network.accessArray
cell. collectionView.reloadData()
i have a table view and i have placed a collection view inside the cell, i'm getting data from API and that data i'm passing to table view and collection view but when i run the app it crashes with this error,
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Lawon.KnowledgeVC collectionView:numberOfItemsInSection:]: unrecognized selector sent to instance 0x7fa90af0cbc0
My code for table view,
extension KnowledgeVC : UITableViewDelegate,UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return categoryArray.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categoryArray.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 35
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = Bundle.main.loadNibNamed("KnowledgeHeaderTVC", owner: self, options: nil)?.first as! KnowledgeHeaderTVC
headerView.categoryNameLbl.text = categoryArray[section].catName
headerView.articlesLbl.text = "\(categoryArray[section].blogArray.count)" + "articles"
return headerView
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = knowledgeTableView.dequeueReusableCell(withIdentifier: "KnowledgeCell", for: indexPath) as! KnowledgeDetailTVC
cell.categoryArray = categoryArray
return cell
}
}
This is my table view cell class where i have mad outlet for collection view and populating data in it and calling its delegate and datasource,
class KnowledgeDetailTVC: UITableViewCell,UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var categoryCollectionView : UICollectionView!
var categoryArray = [Category]()
override func awakeFromNib() {
super.awakeFromNib()
self.categoryCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(categoryArray[section].blogArray.count)
return categoryArray[section].blogArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "familyCell", for: indexPath) as! FamilyCVC
cell.categoryLbl.text = categoryArray[indexPath.section].blogArray[indexPath.row].articleTitle
let imageUrl = categoryArray[indexPath.section].blogArray[indexPath.row].imageUrl!
print(imageUrl)
cell.categoryImage.sd_setImage(with: URL(string: imageUrl), placeholderImage: UIImage(named: "person.jpeg"))
// cell.bgView.layer.masksToBounds = true
// cell.bgView.layer.shadowColor = UIColor.black.cgColor
// cell.bgView.layer.shadowOpacity = 3
// cell.bgView.layer.shadowOffset = CGSize(width: -1, height: 1)
// cell.bgView.layer.shadowRadius = 2
// cell.bgView.layer.shouldRasterize = true
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
You may set the delegate & dataSource of the collectionView in the prototype cell to the KnowledgeVC in IB while implementation is inside the cell , but you should set them in awakeFromNib
self.categoryCollectionView.delegate = self
self.categoryCollectionView.dataSource = self
self.categoryCollectionView.reloadData()
Also it's better to refresh it inside cellForRowAt to avoid dequeuing problems
cell.categoryArray = categoryArray
cell.categoryCollectionView.reloadData()
There is no compile time error thrown in that case and that is a big problem of setting the delegate and dataSource in IB
I have implemented a collection view within a UITableViewCell. I want the table section header index or header title inside collectionView(_:cellForItemAt:)
Here is my table view code:
extension ContentCatVCViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return categories.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CategoryRow
print("table row index:: \(indexPath.row)")
return cell
}
func tableView(_ tableView: UITableView, willDisplayHeaderView view:UIView, forSection: Int) {
if let headerTitle = view as? UITableViewHeaderFooterView {
headerTitle.textLabel?.textColor = UIColor.clear
}
}
}
Here is my table cell code:
extension CategoryRow : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath) as! VideoCell
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor(red:222/255, green:225/255, blue:227/255, alpha: 1).cgColor
return cell
}
}
How to get the tableView(_:titleForHeaderInSection:) inside collectionView(_:cellForItemAt:) function. Please help.
In cellForRowAt method you are loading CollectionView. Means you are getting IndexPath where you are loading CollectionViews. So indexPath.section will be your header index for each CollectionView.
After following a guide on how to add collectionViews inside a tableViewCell (here) and then I tried to see if I can switch these two cells.
However, when I try to scroll down the collectionview(horizontally) I get an error that the collectionview index goes out of bounds. I tried to see if adding a reload data for each collection view would help with that issue, but it doesn't... Code below:
class BuildTravelPackage: UIViewController, UITableViewDataSource,UITableViewDelegate, UICollectionViewDelegate {
#IBOutlet var optionsTableView: UITableView!
var items = [[PackageOption]]()
override func viewDidLoad() {
super.viewDidLoad()
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPress(longPressGestureRecognizer:)))
self.optionsTableView.addGestureRecognizer(longPressRecognizer)
//load data into cells
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.alpha = 0
UIView.animate(withDuration: 1.0) {
cell.alpha = 1.0
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 175
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return .none
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let item = items[sourceIndexPath.row]
items.remove(at: sourceIndexPath.row)
items.insert(item, at: destinationIndexPath.row)
optionsTableView.isEditing = !optionsTableView.isEditing
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = optionsTableView.dequeueReusableCell(withIdentifier: "optionCell", for: indexPath) as! PackageOptionTableViewCell
cell.collectionView.delegate = self
cell.collectionView.dataSource = self
cell.collectionView.tag = indexPath.row
cell.collectionView.reloadData()
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Column:",indexPath.row)
print("Row:",collectionView.tag)
//highlght selected cell and load a new cell with infomation? Or load a uiview with date selection
}
func longPress(longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: self.view)
if let indexPath = optionsTableView.indexPathForRow(at: touchPoint) {
optionsTableView.isEditing = !optionsTableView.isEditing
}
}
}
}
extension BuildTravelPackage:UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items[collectionView.tag].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "singleOptionCell", for: indexPath) as! OptionCollectionViewCell
cell.image.image = items[collectionView.tag][indexPath.row].imageFile
cell.label.text = items[collectionView.tag][indexPath.row].name
return cell
}
}
I think problem is here when you are replacing objects
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let item = items[sourceIndexPath.row]
items.remove(at: sourceIndexPath.row)
items.insert(item, at: destinationIndexPath.row)
optionsTableView.isEditing = !optionsTableView.isEditing
}
try replacing code by
swap(& items[sourceIndexPath.row], & items[destinationIndexPath.row])
Im working on a project in swift 3 and it contains a UICollectionview inside a UItableViewCell. Therefore I have three Class in the order of UIViewController,UITableViewCell,UICollectionViewCell. The codes of the the classes as bellow.
UIViewController
extension ViewController : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 160
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return (section%2 == 0) ? "Games":"Love"
}
UITableViewCell
extension TableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageNames.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.naeLabel.text = imageNames [indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let clickedIndex = imageNames[indexPath.row]
print(clickedIndex)
}
}
My requirement is to pass an array from UIViewController to UITableViewCell. How could I achieve this?