Populating dynamic data in CollectionView which is inside TableView - ios

Main View Controller
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return CategoryNames.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell=tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath as IndexPath) as! CategoryTableViewCell
cell.lblCategoryName.text = CategoryNames[indexPath.row] as? String
cell.ViewCategogyBackground.layer.cornerRadius=20
cell.ViewCategogyBackground.layer.maskedCorners = [.layerMaxXMinYCorner]
cell.arrayForCollectionView = [["xx","yy"],["zz","vv","tt"],["hello"],["11","44"]]
cell.reloadCollectionView()
return cell
}
Table View Cell
var arrayForCollectionView : [[String]]!
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 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CategoryItemCollectionViewCell
let rowValue = arrayForCollectionView[indexPath.row]
for i in 0..<rowValue.count {
cell.lblItemName.text = rowValue[i] as? String
}
return cell
}
Outputhere is my output I want to display data like first section of 2D array under t1(Category 1) and second section under t2(category 2). both categories and items in collection view are dynamic

You need to create a CollectionView inside TableView and create outlet of collectionView inside tableViewCell like this:
class TimingSlotsTVCell: UITableViewCell
{
#IBOutlet weak var timeSlotsCV: UICollectionView!
}
Now in your cellForRow of tableView do this:
let cell = tableView.dequeueReusableCell(withIdentifier: "TimingSlotsTVCell") as! TimingSlotsTVCell
cell.timeSlotsCV.reloadData()
return cell
Now collectionView cell will be called from inside tableView

Related

Find in which row of a tableView is a CollectionView

I'm asking for your help because I blocked with something in my Swift App.
I would like to parse an array with some meals.
My array is the next one:
let meals_list: [[String]] = [
["breakfast", "snack_1", "pre_intra_post", "lunch", "snack_2", "diner"],
["breakfast", "snack_1", "lunch", "snack_2", "diner"]
]
As you can see, there are 6 items in the first part, and 5 items in the second one.
These meals are going to be displayed in a horizontal CollectionView.
Each CollectionView needs to be in a table view.
So, I would like to create 6 cards in my first collection view
And 5 cards in my second collection view.
Here is how I manage everything
//Manage meals content
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0{
return 6
} else {
return 5
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! Meal_vc_cell
return cell
}
//Manage day type content (train/rest)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "food_plan_cell", for: indexPath) as! FoodPlanCell
if (indexPath.row == 0){
cell.meals_day_type.text = "Vos repas les\r\njours d'entraînement".uppercased()
} else {
cell.meals_day_type.text = "Vos repas les\r\njours de Repos".uppercased()
}
return cell
}
private func tableView(tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? FoodPlanCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: indexPath.row)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collection_cell", for: indexPath) as! Meal_vc_cell
cell.meal.text = meals_list.[indexPath.section][indexPath.item]
return cell
}

retain scroll position for nested collectionView

After the tableView.reloadData() the visible collectionView display the first row unexpected immediately.
Im building a tableView contains collectionView in its cells, users can scroll multiple images in every single tableView just like Instagram. How can I fix it? Thanks!
tableView DataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return photoRolls.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! HomeTableViewCell
if photoRolls.isEmpty {
return UITableViewCell()
}
let user: UserModel = users[indexPath.row]
let photoRoll: PhotoRoll = photoRolls[indexPath.row] //this Model contains post info: likes, comments etc.
let photoUrls: UrlStrings = urls[indexPath.row] //this Model contains a array of urlStrings for each collectionView inside the tableViewCell
cell.urlStrings = photoUrls
cell.photoRoll = photoRoll
cell.user = user
cell.delegate = self
return cell
}
prepareForReuse Method in tableViewCell
override func prepareForReuse() {
super.prepareForReuse()
captionLabel.text = nil
profileImage.image = UIImage(named: "placeholderImg")
profileImageRight.image = UIImage(named: "placeholderImg")
collectionView.scrollToItem(at:IndexPath(item: 0, section: 0), at: .left, animated: false)//tried to remove this method, but the collectionView would not display the first row when it's visible
}
DataSource of collectionView inside tableViewCell
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cellUrlArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionViewCell", for: indexPath) as! HomeCollectionViewCell
cell.url = cellUrlArray[indexPath.row]
return cell
}
Like the question title said. I expect the visible collectionView stays on the current row after the tableView load more data after tableView.reloadData() is called! Thanks again!
I think it is possible with contentOffset cacheing, like below
var cachedPosition = Dictionary<IndexPath,CGPoint>()
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let cell = cell as? HomeTableViewCell {
cachedPosition[indexPath] = cell.collectionView.contentOffset
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
<<Your Code>>
cell.collectionView.contentOffset = cachedPosition[indexPath] ?? .zero
return cell
}

Shortage on UITableView cell count

I am currently using two prototype cells to have my collectionView in top cell moving horizontally while all other cells moves vertical. It's still short one cell count at the bottom and I can't seem to figure out why.
This is the code. Can you point out where the issue is please?
//Mark:- Data arrays
var dataArray: [String] = ["c1","c2","c3","c4","c5"]
var cellArray: [String] = ["10","11","12","13","14","15"]
//Mark:- UITableView Delegate
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row])
return cell2
}
}
//Mark:- UICollectionView Delegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InsideCollectionViewCell", for: indexPath) as! InsideCollectionViewCell
cell.myImage.image = UIImage(named: dataArray[indexPath.row])
return cell
}
It seems you want your table view to contain the values in your cellArray array plus one extra special row at index 0.
In order to do this you need to indicate that there is an extra row and your indexing needs to account for the extra row.
But a simpler approach is to use multiple sections in your table view. Use section 0 for the extra special row and use section 1 for the values in your cellArray.
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section == 0 ? 1 : cellArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row])
return cell2
}
}
Make sure you adjust for the use of multiple sections in any other table view method you may implement (such as didSelectRowAt, etc.).
For the sake of comparison, here is how you would need to change your code if you want all of the rows in one section:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellArray.count + 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell") as! MainTableViewCell
return cell
} else {
let cell2 = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell") as! CustomTableViewCell
cell2.cellImage.image = UIImage(named: cellArray[indexPath.row - 1])
return cell2
}
}

How can I figure out which tableView Cell is selected when collectionview is scrolled horizontally

I have collectionView inside TableViewCell.
TableView has 1 section and 4 rows.
I want to figure out which row of tableviewcell is selected when collectionView is Scrolled Horizontally.
I tryed to figure out by putting tableView row in "var nowRow" variable like below code. But It does not work.
How can I find out which row of tableviewcell is selected?
class Home2ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
var posts = [Post]()
var nowRow = Int()
override func viewDidLoad() {
// get posts elements here
//posts.append(element).......
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count // 4counts
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = DetailMutiTableViewCell()
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailMutiTableViewCell", for: indexPath) as! DetailMutiTableViewCell
nowRow = indexPath.row
cell.post = posts[nowRow]
cell.collectionView1.delegate = self
cell.collectionView1.dataSource = self
cell.collectionView1.reloadData()
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts[nowRow].imageUrls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MultiImagesCollectionViewCell", for: indexPath) as! MultiImagesCollectionViewCell
let photoUrlString = posts[nowRow].imageUrls[indexPath.item] // ←error occured
let photoUrl = URL(string: photoUrlString)
cell.imageView1.sd_setImage(with: photoUrl)
return cell
}
}
editeditedit
As you have no doubt discovered, interacting with the collectionViews in your table rows does not trigger the tableView method tableView(_:didSelectRowAt:), and tableView.indexPathForSelectedRow is nil because no row has been selected. You need a way to map from the collectionView to the indexPath.row that contains it. This information is known at tableViewCell setup time.
Add a dictionary to your Home2ViewController that maps a UICollectionView to a row Int:
var collectionViewRow = [UICollectionView : Int]()
Add the entries in tableView(_:cellForRowAt:) where you know the row and collectionView:
collectionViewRow[cell.collectionView1] = indexPath.row
Then, anytime you have a collectionView, you can look up its row:
let row = collectionViewRow[collectionView]!
Here's the whole code:
class Home2ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
var posts = [Post]()
var collectionViewRow = [UICollectionView : Int]()
override func viewDidLoad() {
// get posts elements here
//posts.append(element).......
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count // 4counts
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = DetailMutiTableViewCell()
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailMutiTableViewCell", for: indexPath) as! DetailMutiTableViewCell
collectionViewRow[cell.collectionView1] = indexPath.row
cell.post = posts[indexPath.row]
cell.collectionView1.delegate = self
cell.collectionView1.dataSource = self
cell.collectionView1.reloadData()
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let row = collectionViewRow[collectionView]!
return posts[row].imageUrls.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MultiImagesCollectionViewCell", for: indexPath) as! MultiImagesCollectionViewCell
let row = collectionViewRow[collectionView]!
let photoUrlString = posts[row].imageUrls[indexPath.item] // ←error occured
let photoUrl = URL(string: photoUrlString)
cell.imageView1.sd_setImage(with: photoUrl)
return cell
}
}
Notes:
The force unwrap of the dictionary lookup won't fail because the collectionView will be in there. If you want to unwrap it with if let, you'll need to decide what to do when you don't get a row (which shouldn't happen).
This method could fail if your table allows editing (user can rearrange order of rows or delete rows). If you don't support editing, then this will work fine. To support editing, you could change the dictionary to [UICollectionView : UITableViewCell]. Then, given a UICollectionView, you could look up its cell, and then call let indexPath = tableView.indexPath(for: cell) to get the indexPath and your row is then just indexPath.row.

Swift3 iOS -How to get Data from All IndexPaths from TableView Before Cell Is Pressed

I followed Ash Furrows tutorial collectionView inside tableView
I have TableItem class that has a name property and an array of URLs. I have a tableView that has collectionView inside of it.
I vertically populate my tableview with the whatever amount of TableItems are available and I horizontally populate my collectionView with however many amount of urls that are inside the array from the TableItem class.
I'm not concerned with pressing a table cell and then getting the information, I want the data to be displayed simultaneously in both collections.
How can I pull the TableItem data and display it in the collectionView at the same time as the tableView?
class TableItem{
var name: String?
var urlsForCollection: [URl] = []
}
var tableItems = [TableItem]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath) as! TableCell
cell.textLabel.text = tableItems[indexPath.row].name
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//how do I return the urlsForCollection.count from each TableItem in tableItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
//how can I access the urlsForCollection for each TableItem in tableItems
for url in urlsForCollection{
imageView.sd_setImage(with: url!)
}
return cell
}
Like this:
let tableItem = tableItems[indexPath.row] as! TableItem
for url in tableItem.urlsForCollection{
imageView.sd_setImage(with: url!)
}
Should work.

Resources