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?
Related
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.
I am created UICollectionView inside of UITableView ,populating array values in UItableview is working perfect, when trying to populate a array values into collectionView getting same values in collectionView of all the rows of tableView, I want to populate a zeroth index array in collectionview of zeroth row UItableview and so on
below I tried a sample,
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UICollectionViewDelegate,UICollectionViewDataSource{
let array = ["product 1","product 2","product 3","product4"]
let array1 = ["product id 1","product id 2","product id 3","product id 4"]
let array2 = [["product id 1","product id 2"],["product id 3","product id 4"],["product id 5","product id 6"],["product id 7","product id 8","product id 9","product id 10","product id 11"]] as [NSArray]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cells") as! TableViewCell
cell.tableviewlabel1.text = array[indexPath.row]
cell.tableviewlabel2.text = array1[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return array2.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection", for: indexPath) as! CollectionViewCell
let rowValue : NSArray = array2[indexPath.row]
for i in 0..<rowValue.count {
cell.collectionviewlabel1.text = rowValue[i] as? String
}
return cell
}
For example ,I want a zeroth index of array2 values in collectionview of zeroth row of tableview, and first index values in collectionview of first row of tableview and so on.
First your array2 has to be like this :
let array2 = [["product id 1","product id 2"],["product id 3","product id 4"],["product id 5","product id 6"],["product id 7","product id 8","product id 9","product id 10","product id 11"]]
Don't use NSArray in Swift. you can write it as [String], [[String]].
Your ViewController will have only UITableViewDelegate and UITableViewDatasource methods:
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cells") as! TableViewCell
cell.tableviewlabel1.text = array[indexPath.row]
cell.tableviewlabel2.text = array1[indexPath.row]
cell.arrayForCollectionView = array2
return cell
}
}
Then in your TableViewCell:
class TableViewCell: UITableViewCell {
var arrayForCollectionView : [[String]]! {
didSet {
self.collectionView.reloadData
}
}
#IBOutlet weak var collectionView: UICollectionView!
}
extension TableViewCell : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (arrayForCollectionView != nil) {
return arrayForCollectionView.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection", for: indexPath) as! CollectionViewCell
let rowValue = arrayForCollectionView[indexPath.row]
for i in 0..<rowValue.count {
cell.collectionviewlabel1.text = rowValue[i] as? String
}
return cell
}
}
Let me know if you are getting any issue.
Giving an example for that:
first tableView is inside ViewController
class ViewController: UIViewController {
//MARK:- IBOUTELTS
//MARK:-
#IBOutlet weak var tableView: UITableView!
//MARK:- VARIABLES
//MARK:-
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension YourViewConroller: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
}
And Your CollectionView is inside TableViewCell
extension YourTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
}
}
And make different class for TableView and CollectionView:
class YourTableViewCell: UITableViewCell { // tableview cell
}
classYourCollectionViewCell: UICollectionViewCell { // collectionviewcell
}
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])
I have added UICollectionView in UITableView. Now, I want to identify on which cell the user taps and the indexPath of that UICollectionView.
I'm getting correct indexPath but could not get the tag of on which the UICollectionView he tapped. I'm doing something like this to get tap
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("\(collectionView.tag) ---- \(indexPath.item) ")
}
Whole Code
class UserLibraryViewController: UIViewController {
extension UserLibraryViewController : UITableViewDelegate { }
extension UserLibraryViewController : UITableViewDataSource {
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return myBooksGenre[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return myBooksGenre.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("userBooksTableViewCell") as! UserLibraryTableViewCell
return cell
}
}
TableViewCell
class UserLibraryTableViewCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
}
extension UserLibraryTableViewCell : UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("userBooksCollectionViewCell", forIndexPath: indexPath) as! UserLibraryCollectionViewCell
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("\(collectionView.tag) ---- \(indexPath.item) ")
}
}
extension UserLibraryTableViewCell : UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let itemsPerRow:CGFloat = 4
let hardCodedPadding:CGFloat = 5
let itemWidth = (collectionView.bounds.width / itemsPerRow) - hardCodedPadding
let itemHeight = collectionView.bounds.height - (2 * hardCodedPadding)
return CGSize(width: itemWidth, height: itemHeight)
}
}
You are having multiple section in your tableView, so you can create one NSIndexPath instance in your UserLibraryTableViewCell and initialize it in the cellForRowAtIndexPath like this.
class UserLibraryTableViewCell: UITableViewCell {
var tableIndexPath: NSIndexPath?
}
Now set this tableIndexPath in the cellForRowAtIndexPath.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("userBooksTableViewCell") as! UserLibraryTableViewCell
cell.tableIndexPath = indexPath
return cell
}
Now in didSelectItemAtIndexPath of collectionView access tableIndexPath like this.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("\(self.tableIndexPath) ---- \(indexPath.item) ")
}
Try this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("userBooksTableViewCell") as! UserLibraryTableViewCell
cell.collectionView.tag = indexpath.row
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myBooksGenre.count
}
You are not setting the Tag for the Collection View for the particular cell in the cellForRowAtIndexPath of Table View.
Update the code.
Also conform UICollectionViewDelegate protocol:
extension UserLibraryTableViewCell : UICollectionViewDataSource, UICollectionViewDelegate